1997-12-04 01:34:01 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* user.c
|
2005-06-28 07:09:14 +02:00
|
|
|
* Commands for manipulating roles (formerly called users).
|
1997-12-04 01:34:01 +01:00
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1997-12-04 01:34:01 +01:00
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/commands/user.c
|
1997-12-04 01:34:01 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2001-06-12 07:55:50 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2019-12-27 00:09:00 +01:00
|
|
|
#include "access/genam.h"
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2019-01-21 19:18:20 +01:00
|
|
|
#include "access/table.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "access/xact.h"
|
2013-12-19 22:10:01 +01:00
|
|
|
#include "catalog/binary_upgrade.h"
|
2016-04-08 22:56:27 +02:00
|
|
|
#include "catalog/catalog.h"
|
2005-07-07 22:40:02 +02:00
|
|
|
#include "catalog/dependency.h"
|
2002-08-30 03:01:02 +02:00
|
|
|
#include "catalog/indexing.h"
|
2010-11-25 17:48:49 +01:00
|
|
|
#include "catalog/objectaccess.h"
|
2005-06-28 07:09:14 +02:00
|
|
|
#include "catalog/pg_auth_members.h"
|
|
|
|
#include "catalog/pg_authid.h"
|
2009-10-08 00:14:26 +02:00
|
|
|
#include "catalog/pg_database.h"
|
|
|
|
#include "catalog/pg_db_role_setting.h"
|
2006-02-12 04:22:21 +01:00
|
|
|
#include "commands/comment.h"
|
2009-10-08 00:14:26 +02:00
|
|
|
#include "commands/dbcommands.h"
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
#include "commands/defrem.h"
|
2011-07-20 19:18:24 +02:00
|
|
|
#include "commands/seclabel.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "commands/user.h"
|
Replace isMD5() with a more future-proof way to check if pw is encrypted.
The rule is that if pg_authid.rolpassword begins with "md5" and has the
right length, it's an MD5 hash, otherwise it's a plaintext password. The
idiom has been to use isMD5() to check for that, but that gets awkward,
when we add new kinds of verifiers, like the verifiers for SCRAM
authentication in the pending SCRAM patch set. Replace isMD5() with a new
get_password_type() function, so that when new verifier types are added, we
don't need to remember to modify every place that currently calls isMD5(),
to also recognize the new kinds of verifiers.
Also, use the new plain_crypt_verify function in passwordcheck, so that it
doesn't need to know about MD5, or in the future, about other kinds of
hashes or password verifiers.
Reviewed by Michael Paquier and Peter Eisentraut.
Discussion: https://www.postgresql.org/message-id/2d07165c-1793-e243-a2a9-e45b624c7580@iki.fi
2017-02-01 12:11:37 +01:00
|
|
|
#include "libpq/crypt.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "miscadmin.h"
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "storage/lmgr.h"
|
2005-06-29 22:34:15 +02:00
|
|
|
#include "utils/acl.h"
|
2000-01-14 23:11:38 +01:00
|
|
|
#include "utils/builtins.h"
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
#include "utils/catcache.h"
|
2000-05-28 19:56:29 +02:00
|
|
|
#include "utils/fmgroids.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "utils/syscache.h"
|
2011-09-09 19:23:41 +02:00
|
|
|
#include "utils/timestamp.h"
|
2023-01-10 18:44:49 +01:00
|
|
|
#include "utils/varlena.h"
|
1997-12-04 01:34:01 +01:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
/*
|
|
|
|
* Removing a role grant - or the admin option on it - might recurse to
|
|
|
|
* dependent grants. We use these values to reason about what would need to
|
|
|
|
* be done in such cases.
|
|
|
|
*
|
|
|
|
* RRG_NOOP indicates a grant that would not need to be altered by the
|
|
|
|
* operation.
|
|
|
|
*
|
|
|
|
* RRG_REMOVE_ADMIN_OPTION indicates a grant that would need to have
|
|
|
|
* admin_option set to false by the operation.
|
|
|
|
*
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
* Similarly, RRG_REMOVE_INHERIT_OPTION and RRG_REMOVE_SET_OPTION indicate
|
|
|
|
* grants that would need to have the corresponding options set to false.
|
2022-08-25 16:06:02 +02:00
|
|
|
*
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
* RRG_DELETE_GRANT indicates a grant that would need to be removed entirely
|
|
|
|
* by the operation.
|
|
|
|
*/
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
RRG_NOOP,
|
|
|
|
RRG_REMOVE_ADMIN_OPTION,
|
2022-08-25 16:06:02 +02:00
|
|
|
RRG_REMOVE_INHERIT_OPTION,
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
RRG_REMOVE_SET_OPTION,
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
RRG_DELETE_GRANT
|
|
|
|
} RevokeRoleGrantAction;
|
|
|
|
|
2015-03-11 03:33:25 +01:00
|
|
|
/* Potentially set by pg_upgrade_support functions */
|
2011-01-08 03:59:29 +01:00
|
|
|
Oid binary_upgrade_next_pg_authid_oid = InvalidOid;
|
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
unsigned specified;
|
|
|
|
bool admin;
|
|
|
|
bool inherit;
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
bool set;
|
2022-08-25 16:06:02 +02:00
|
|
|
} GrantRoleOptions;
|
|
|
|
|
|
|
|
#define GRANT_ROLE_SPECIFIED_ADMIN 0x0001
|
|
|
|
#define GRANT_ROLE_SPECIFIED_INHERIT 0x0002
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
#define GRANT_ROLE_SPECIFIED_SET 0x0004
|
2001-06-12 07:55:50 +02:00
|
|
|
|
2023-01-10 18:44:49 +01:00
|
|
|
/* GUC parameters */
|
2020-06-10 16:16:37 +02:00
|
|
|
int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256;
|
2023-01-10 18:44:49 +01:00
|
|
|
char *createrole_self_grant = "";
|
|
|
|
bool createrole_self_grant_enabled = false;
|
2023-05-19 23:24:48 +02:00
|
|
|
GrantRoleOptions createrole_self_grant_options;
|
1998-12-14 07:50:32 +01:00
|
|
|
|
2009-11-18 22:57:56 +01:00
|
|
|
/* Hook to check passwords in CreateRole() and AlterRole() */
|
|
|
|
check_password_hook_type check_password_hook = NULL;
|
|
|
|
|
2023-01-05 20:33:35 +01:00
|
|
|
static void AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
List *memberSpecs, List *memberIds,
|
2022-08-25 16:06:02 +02:00
|
|
|
Oid grantorId, GrantRoleOptions *popt);
|
2023-01-05 20:33:35 +01:00
|
|
|
static void DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
List *memberSpecs, List *memberIds,
|
2022-08-25 16:06:02 +02:00
|
|
|
Oid grantorId, GrantRoleOptions *popt,
|
|
|
|
DropBehavior behavior);
|
2023-01-05 20:30:40 +01:00
|
|
|
static void check_role_membership_authorization(Oid currentUserId, Oid roleid,
|
|
|
|
bool is_grant);
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
static Oid check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId,
|
|
|
|
bool is_grant);
|
|
|
|
static RevokeRoleGrantAction *initialize_revoke_actions(CatCList *memlist);
|
|
|
|
static bool plan_single_revoke(CatCList *memlist,
|
|
|
|
RevokeRoleGrantAction *actions,
|
|
|
|
Oid member, Oid grantor,
|
2022-08-25 16:06:02 +02:00
|
|
|
GrantRoleOptions *popt,
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
DropBehavior behavior);
|
|
|
|
static void plan_member_revoke(CatCList *memlist,
|
|
|
|
RevokeRoleGrantAction *actions, Oid member);
|
|
|
|
static void plan_recursive_revoke(CatCList *memlist,
|
|
|
|
RevokeRoleGrantAction *actions,
|
|
|
|
int index,
|
|
|
|
bool revoke_admin_option_only,
|
|
|
|
DropBehavior behavior);
|
2022-08-25 16:06:02 +02:00
|
|
|
static void InitGrantRoleOptions(GrantRoleOptions *popt);
|
2002-04-04 06:25:54 +02:00
|
|
|
|
|
|
|
|
2014-12-23 19:35:49 +01:00
|
|
|
/* Check if current user has createrole privileges */
|
|
|
|
static bool
|
|
|
|
have_createrole_privilege(void)
|
|
|
|
{
|
|
|
|
return has_createrole_privilege(GetUserId());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* CREATE ROLE
|
1997-12-04 01:34:01 +01:00
|
|
|
*/
|
2012-12-29 13:55:37 +01:00
|
|
|
Oid
|
2016-09-06 18:00:00 +02:00
|
|
|
CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
|
1997-12-04 01:34:01 +01:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
Relation pg_authid_rel;
|
|
|
|
TupleDesc pg_authid_dsc;
|
1998-12-14 07:50:32 +01:00
|
|
|
HeapTuple tuple;
|
2022-07-16 08:42:15 +02:00
|
|
|
Datum new_record[Natts_pg_authid] = {0};
|
|
|
|
bool new_record_nulls[Natts_pg_authid] = {0};
|
2023-01-05 20:33:35 +01:00
|
|
|
Oid currentUserId = GetUserId();
|
2005-06-28 07:09:14 +02:00
|
|
|
Oid roleid;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *item;
|
|
|
|
ListCell *option;
|
2005-06-28 07:09:14 +02:00
|
|
|
char *password = NULL; /* user password */
|
2014-12-23 19:35:49 +01:00
|
|
|
bool issuper = false; /* Make the user a superuser? */
|
|
|
|
bool inherit = true; /* Auto inherit privileges? */
|
|
|
|
bool createrole = false; /* Can this user create roles? */
|
|
|
|
bool createdb = false; /* Can the user create databases? */
|
|
|
|
bool canlogin = false; /* Can this user login? */
|
|
|
|
bool isreplication = false; /* Is this a replication role? */
|
|
|
|
bool bypassrls = false; /* Is this a row security enabled role? */
|
2005-07-31 19:19:22 +02:00
|
|
|
int connlimit = -1; /* maximum connections allowed */
|
2005-06-28 21:51:26 +02:00
|
|
|
List *addroleto = NIL; /* roles to make this a member of */
|
|
|
|
List *rolemembers = NIL; /* roles to be members of this role */
|
|
|
|
List *adminmembers = NIL; /* roles to be admins of this role */
|
|
|
|
char *validUntil = NULL; /* time the login is valid until */
|
2009-11-18 22:57:56 +01:00
|
|
|
Datum validUntil_datum; /* same, as timestamptz Datum */
|
|
|
|
bool validUntil_null;
|
2001-08-15 20:42:16 +02:00
|
|
|
DefElem *dpassword = NULL;
|
2005-06-29 22:34:15 +02:00
|
|
|
DefElem *dissuper = NULL;
|
2005-07-26 18:38:29 +02:00
|
|
|
DefElem *dinherit = NULL;
|
2005-06-28 07:09:14 +02:00
|
|
|
DefElem *dcreaterole = NULL;
|
2005-06-29 22:34:15 +02:00
|
|
|
DefElem *dcreatedb = NULL;
|
2005-06-28 07:09:14 +02:00
|
|
|
DefElem *dcanlogin = NULL;
|
2010-12-29 11:05:03 +01:00
|
|
|
DefElem *disreplication = NULL;
|
2005-07-31 19:19:22 +02:00
|
|
|
DefElem *dconnlimit = NULL;
|
2005-06-28 21:51:26 +02:00
|
|
|
DefElem *daddroleto = NULL;
|
|
|
|
DefElem *drolemembers = NULL;
|
|
|
|
DefElem *dadminmembers = NULL;
|
2001-08-15 20:42:16 +02:00
|
|
|
DefElem *dvalidUntil = NULL;
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
DefElem *dbypassRLS = NULL;
|
2023-05-19 23:24:48 +02:00
|
|
|
GrantRoleOptions popt;
|
2001-07-11 00:09:29 +02:00
|
|
|
|
2014-12-23 19:35:49 +01:00
|
|
|
/* The defaults can vary depending on the original statement type */
|
2005-07-26 18:38:29 +02:00
|
|
|
switch (stmt->stmt_type)
|
|
|
|
{
|
|
|
|
case ROLESTMT_ROLE:
|
|
|
|
break;
|
|
|
|
case ROLESTMT_USER:
|
2014-12-23 19:35:49 +01:00
|
|
|
canlogin = true;
|
2005-07-26 18:38:29 +02:00
|
|
|
/* may eventually want inherit to default to false here */
|
|
|
|
break;
|
|
|
|
case ROLESTMT_GROUP:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-07-11 00:09:29 +02:00
|
|
|
/* Extract options from the statement node tree */
|
|
|
|
foreach(option, stmt->options)
|
|
|
|
{
|
|
|
|
DefElem *defel = (DefElem *) lfirst(option);
|
|
|
|
|
Remove support for password_encryption='off' / 'plain'.
Storing passwords in plaintext hasn't been a good idea for a very long
time, if ever. Now seems like a good time to finally forbid it, since we're
messing with this in PostgreSQL 10 anyway.
Remove the CREATE/ALTER USER UNENCRYPTED PASSSWORD 'foo' syntax, since
storing passwords unencrypted is no longer supported. ENCRYPTED PASSWORD
'foo' is still accepted, but ENCRYPTED is now just a noise-word, it does
the same as just PASSWORD 'foo'.
Likewise, remove the --unencrypted option from createuser, but accept
--encrypted as a no-op for backward compatibility. AFAICS, --encrypted was
a no-op even before this patch, because createuser encrypted the password
before sending it to the server even if --encrypted was not specified. It
added the ENCRYPTED keyword to the SQL command, but since the password was
already in encrypted form, it didn't make any difference. The documentation
was not clear on whether that was intended or not, but it's moot now.
Also, while password_encryption='on' is still accepted as an alias for
'md5', it is now marked as hidden, so that it is not listed as an accepted
value in error hints, for example. That's not directly related to removing
'plain', but it seems better this way.
Reviewed by Michael Paquier
Discussion: https://www.postgresql.org/message-id/16e9b768-fd78-0b12-cfc1-7b6b7f238fde@iki.fi
2017-05-08 10:26:07 +02:00
|
|
|
if (strcmp(defel->defname, "password") == 0)
|
2001-09-19 11:48:42 +02:00
|
|
|
{
|
2001-08-15 20:42:16 +02:00
|
|
|
if (dpassword)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2001-08-15 20:42:16 +02:00
|
|
|
dpassword = defel;
|
|
|
|
}
|
2001-09-19 11:48:42 +02:00
|
|
|
else if (strcmp(defel->defname, "sysid") == 0)
|
|
|
|
{
|
2005-07-26 18:38:29 +02:00
|
|
|
ereport(NOTICE,
|
2005-06-28 07:09:14 +02:00
|
|
|
(errmsg("SYSID can no longer be specified")));
|
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
else if (strcmp(defel->defname, "superuser") == 0)
|
|
|
|
{
|
|
|
|
if (dissuper)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-29 22:34:15 +02:00
|
|
|
dissuper = defel;
|
|
|
|
}
|
2005-07-26 18:38:29 +02:00
|
|
|
else if (strcmp(defel->defname, "inherit") == 0)
|
|
|
|
{
|
|
|
|
if (dinherit)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-07-26 18:38:29 +02:00
|
|
|
dinherit = defel;
|
|
|
|
}
|
2005-06-28 07:09:14 +02:00
|
|
|
else if (strcmp(defel->defname, "createrole") == 0)
|
|
|
|
{
|
|
|
|
if (dcreaterole)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-28 07:09:14 +02:00
|
|
|
dcreaterole = defel;
|
2001-08-15 20:42:16 +02:00
|
|
|
}
|
2001-09-19 11:48:42 +02:00
|
|
|
else if (strcmp(defel->defname, "createdb") == 0)
|
|
|
|
{
|
2001-08-15 20:42:16 +02:00
|
|
|
if (dcreatedb)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2001-08-15 20:42:16 +02:00
|
|
|
dcreatedb = defel;
|
|
|
|
}
|
2005-06-28 07:09:14 +02:00
|
|
|
else if (strcmp(defel->defname, "canlogin") == 0)
|
2001-09-19 11:48:42 +02:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
if (dcanlogin)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-28 07:09:14 +02:00
|
|
|
dcanlogin = defel;
|
2001-08-15 20:42:16 +02:00
|
|
|
}
|
2010-12-29 11:05:03 +01:00
|
|
|
else if (strcmp(defel->defname, "isreplication") == 0)
|
|
|
|
{
|
|
|
|
if (disreplication)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2010-12-29 11:05:03 +01:00
|
|
|
disreplication = defel;
|
|
|
|
}
|
2005-07-31 19:19:22 +02:00
|
|
|
else if (strcmp(defel->defname, "connectionlimit") == 0)
|
|
|
|
{
|
|
|
|
if (dconnlimit)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-07-31 19:19:22 +02:00
|
|
|
dconnlimit = defel;
|
|
|
|
}
|
2005-06-28 21:51:26 +02:00
|
|
|
else if (strcmp(defel->defname, "addroleto") == 0)
|
2001-09-19 11:48:42 +02:00
|
|
|
{
|
2005-06-28 21:51:26 +02:00
|
|
|
if (daddroleto)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-28 21:51:26 +02:00
|
|
|
daddroleto = defel;
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
2005-06-28 21:51:26 +02:00
|
|
|
else if (strcmp(defel->defname, "rolemembers") == 0)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
2005-06-28 21:51:26 +02:00
|
|
|
if (drolemembers)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-28 21:51:26 +02:00
|
|
|
drolemembers = defel;
|
|
|
|
}
|
|
|
|
else if (strcmp(defel->defname, "adminmembers") == 0)
|
|
|
|
{
|
|
|
|
if (dadminmembers)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-28 21:51:26 +02:00
|
|
|
dadminmembers = defel;
|
2001-08-15 20:42:16 +02:00
|
|
|
}
|
2001-09-19 11:48:42 +02:00
|
|
|
else if (strcmp(defel->defname, "validUntil") == 0)
|
|
|
|
{
|
2001-08-15 20:42:16 +02:00
|
|
|
if (dvalidUntil)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2001-08-15 20:42:16 +02:00
|
|
|
dvalidUntil = defel;
|
|
|
|
}
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
else if (strcmp(defel->defname, "bypassrls") == 0)
|
|
|
|
{
|
|
|
|
if (dbypassRLS)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
dbypassRLS = defel;
|
|
|
|
}
|
2001-08-15 20:42:16 +02:00
|
|
|
else
|
2003-07-19 01:20:33 +02:00
|
|
|
elog(ERROR, "option \"%s\" not recognized",
|
2001-08-15 20:42:16 +02:00
|
|
|
defel->defname);
|
|
|
|
}
|
|
|
|
|
2005-12-23 17:46:39 +01:00
|
|
|
if (dpassword && dpassword->arg)
|
2005-06-29 22:34:15 +02:00
|
|
|
password = strVal(dpassword->arg);
|
|
|
|
if (dissuper)
|
2022-01-14 10:46:49 +01:00
|
|
|
issuper = boolVal(dissuper->arg);
|
2005-07-26 18:38:29 +02:00
|
|
|
if (dinherit)
|
2022-01-14 10:46:49 +01:00
|
|
|
inherit = boolVal(dinherit->arg);
|
2005-06-28 07:09:14 +02:00
|
|
|
if (dcreaterole)
|
2022-01-14 10:46:49 +01:00
|
|
|
createrole = boolVal(dcreaterole->arg);
|
2005-06-29 22:34:15 +02:00
|
|
|
if (dcreatedb)
|
2022-01-14 10:46:49 +01:00
|
|
|
createdb = boolVal(dcreatedb->arg);
|
2005-06-28 07:09:14 +02:00
|
|
|
if (dcanlogin)
|
2022-01-14 10:46:49 +01:00
|
|
|
canlogin = boolVal(dcanlogin->arg);
|
2010-12-29 11:05:03 +01:00
|
|
|
if (disreplication)
|
2022-01-14 10:46:49 +01:00
|
|
|
isreplication = boolVal(disreplication->arg);
|
2005-07-31 19:19:22 +02:00
|
|
|
if (dconnlimit)
|
2009-01-30 18:24:47 +01:00
|
|
|
{
|
2005-07-31 19:19:22 +02:00
|
|
|
connlimit = intVal(dconnlimit->arg);
|
2009-01-30 18:24:47 +01:00
|
|
|
if (connlimit < -1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("invalid connection limit: %d", connlimit)));
|
|
|
|
}
|
2005-06-28 21:51:26 +02:00
|
|
|
if (daddroleto)
|
|
|
|
addroleto = (List *) daddroleto->arg;
|
|
|
|
if (drolemembers)
|
|
|
|
rolemembers = (List *) drolemembers->arg;
|
|
|
|
if (dadminmembers)
|
|
|
|
adminmembers = (List *) dadminmembers->arg;
|
2005-06-29 22:34:15 +02:00
|
|
|
if (dvalidUntil)
|
|
|
|
validUntil = strVal(dvalidUntil->arg);
|
2014-12-23 19:35:49 +01:00
|
|
|
if (dbypassRLS)
|
2022-01-14 10:46:49 +01:00
|
|
|
bypassrls = boolVal(dbypassRLS->arg);
|
1999-04-02 08:16:36 +02:00
|
|
|
|
2014-12-23 19:35:49 +01:00
|
|
|
/* Check some permissions first */
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (!superuser_arg(currentUserId))
|
2014-12-23 19:35:49 +01:00
|
|
|
{
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (!has_createrole_privilege(currentUserId))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to create role"),
|
|
|
|
errdetail("Only roles with the %s attribute may create roles.",
|
|
|
|
"CREATEROLE")));
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (issuper)
|
2014-12-23 19:35:49 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to create role"),
|
|
|
|
errdetail("Only roles with the %s attribute may create roles with %s.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (createdb && !have_createdb_privilege())
|
2014-12-23 19:35:49 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to create role"),
|
|
|
|
errdetail("Only roles with the %s attribute may create roles with %s.",
|
|
|
|
"CREATEDB", "CREATEDB")));
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (isreplication && !has_rolreplication(currentUserId))
|
2014-12-23 19:35:49 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to create role"),
|
|
|
|
errdetail("Only roles with the %s attribute may create roles with %s.",
|
|
|
|
"REPLICATION", "REPLICATION")));
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (bypassrls && !has_bypassrls_privilege(currentUserId))
|
2014-12-23 19:35:49 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to create role"),
|
|
|
|
errdetail("Only roles with the %s attribute may create roles with %s.",
|
|
|
|
"BYPASSRLS", "BYPASSRLS")));
|
2014-12-23 19:35:49 +01:00
|
|
|
}
|
2000-01-14 23:11:38 +01:00
|
|
|
|
2016-04-08 22:56:27 +02:00
|
|
|
/*
|
|
|
|
* Check that the user is not trying to create a role in the reserved
|
|
|
|
* "pg_" namespace.
|
|
|
|
*/
|
|
|
|
if (IsReservedName(stmt->role))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_RESERVED_NAME),
|
|
|
|
errmsg("role name \"%s\" is reserved",
|
|
|
|
stmt->role),
|
|
|
|
errdetail("Role names starting with \"pg_\" are reserved.")));
|
|
|
|
|
Add an enforcement mechanism for global object names in regression tests.
In commit 18555b132 we tentatively established a rule that regression
tests should use names containing "regression" for databases, and names
starting with "regress_" for all other globally-visible object names, so
as to circumscribe the side-effects that "make installcheck" could have
on an existing installation.
This commit adds a simple enforcement mechanism for that rule: if the code
is compiled with ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS defined, it
will emit a warning (not an error) whenever a database, role, tablespace,
subscription, or replication origin name is created that doesn't obey the
rule. Running one or more buildfarm members with that symbol defined
should be enough to catch new violations, at least in the regular
regression tests. Most TAP tests wouldn't notice such warnings, but
that's actually fine because TAP tests don't execute against an existing
server anyway.
Since it's already the case that running src/test/modules/ tests in
installcheck mode is deprecated, we can use that as a home for tests
that seem unsafe to run against an existing server, such as tests that
might have side-effects on existing roles. Document that (though this
commit doesn't in itself make it any less safe than before).
Update regress.sgml to define these restrictions more clearly, and
to clean up assorted lack-of-up-to-date-ness in its descriptions of
the available regression tests.
Discussion: https://postgr.es/m/16638.1468620817@sss.pgh.pa.us
2019-06-29 17:34:00 +02:00
|
|
|
/*
|
|
|
|
* If built with appropriate switch, whine when regression-testing
|
|
|
|
* conventions for role names are violated.
|
|
|
|
*/
|
|
|
|
#ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
|
|
|
|
if (strncmp(stmt->role, "regress_", 8) != 0)
|
|
|
|
elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
|
|
|
|
#endif
|
|
|
|
|
1998-02-25 14:09:49 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* Check the pg_authid relation to be certain the role doesn't already
|
2006-05-04 18:07:29 +02:00
|
|
|
* exist.
|
1997-12-04 01:34:01 +01:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
|
2005-06-28 07:09:14 +02:00
|
|
|
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2010-08-05 16:45:09 +02:00
|
|
|
if (OidIsValid(get_role_oid(stmt->role, true)))
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
2005-06-28 07:09:14 +02:00
|
|
|
errmsg("role \"%s\" already exists",
|
|
|
|
stmt->role)));
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2009-11-18 22:57:56 +01:00
|
|
|
/* Convert validuntil to internal form */
|
|
|
|
if (validUntil)
|
|
|
|
{
|
|
|
|
validUntil_datum = DirectFunctionCall3(timestamptz_in,
|
|
|
|
CStringGetDatum(validUntil),
|
|
|
|
ObjectIdGetDatum(InvalidOid),
|
|
|
|
Int32GetDatum(-1));
|
|
|
|
validUntil_null = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
validUntil_datum = (Datum) 0;
|
|
|
|
validUntil_null = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Call the password checking hook if there is one defined
|
|
|
|
*/
|
|
|
|
if (check_password_hook && password)
|
|
|
|
(*check_password_hook) (stmt->role,
|
|
|
|
password,
|
Replace isMD5() with a more future-proof way to check if pw is encrypted.
The rule is that if pg_authid.rolpassword begins with "md5" and has the
right length, it's an MD5 hash, otherwise it's a plaintext password. The
idiom has been to use isMD5() to check for that, but that gets awkward,
when we add new kinds of verifiers, like the verifiers for SCRAM
authentication in the pending SCRAM patch set. Replace isMD5() with a new
get_password_type() function, so that when new verifier types are added, we
don't need to remember to modify every place that currently calls isMD5(),
to also recognize the new kinds of verifiers.
Also, use the new plain_crypt_verify function in passwordcheck, so that it
doesn't need to know about MD5, or in the future, about other kinds of
hashes or password verifiers.
Reviewed by Michael Paquier and Peter Eisentraut.
Discussion: https://www.postgresql.org/message-id/2d07165c-1793-e243-a2a9-e45b624c7580@iki.fi
2017-02-01 12:11:37 +01:00
|
|
|
get_password_type(password),
|
2009-11-18 22:57:56 +01:00
|
|
|
validUntil_datum,
|
|
|
|
validUntil_null);
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
|
|
|
* Build a tuple to insert
|
|
|
|
*/
|
2005-06-28 07:09:14 +02:00
|
|
|
new_record[Anum_pg_authid_rolname - 1] =
|
|
|
|
DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
|
|
|
|
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
|
|
|
|
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
|
|
|
|
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
|
|
|
|
new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
|
|
|
|
new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
|
2005-07-31 19:19:22 +02:00
|
|
|
new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2001-07-11 00:09:29 +02:00
|
|
|
if (password)
|
2001-08-15 20:42:16 +02:00
|
|
|
{
|
Replace isMD5() with a more future-proof way to check if pw is encrypted.
The rule is that if pg_authid.rolpassword begins with "md5" and has the
right length, it's an MD5 hash, otherwise it's a plaintext password. The
idiom has been to use isMD5() to check for that, but that gets awkward,
when we add new kinds of verifiers, like the verifiers for SCRAM
authentication in the pending SCRAM patch set. Replace isMD5() with a new
get_password_type() function, so that when new verifier types are added, we
don't need to remember to modify every place that currently calls isMD5(),
to also recognize the new kinds of verifiers.
Also, use the new plain_crypt_verify function in passwordcheck, so that it
doesn't need to know about MD5, or in the future, about other kinds of
hashes or password verifiers.
Reviewed by Michael Paquier and Peter Eisentraut.
Discussion: https://www.postgresql.org/message-id/2d07165c-1793-e243-a2a9-e45b624c7580@iki.fi
2017-02-01 12:11:37 +01:00
|
|
|
char *shadow_pass;
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
const char *logdetail = NULL;
|
Don't allow logging in with empty password.
Some authentication methods allowed it, others did not. In the client-side,
libpq does not even try to authenticate with an empty password, which makes
using empty passwords hazardous: an administrator might think that an
account with an empty password cannot be used to log in, because psql
doesn't allow it, and not realize that a different client would in fact
allow it. To clear that confusion and to be be consistent, disallow empty
passwords in all authentication methods.
All the authentication methods that used plaintext authentication over the
wire, except for BSD authentication, already checked that the password
received from the user was not empty. To avoid forgetting it in the future
again, move the check to the recv_password_packet function. That only
forbids using an empty password with plaintext authentication, however.
MD5 and SCRAM need a different fix:
* In stable branches, check that the MD5 hash stored for the user does not
not correspond to an empty string. This adds some overhead to MD5
authentication, because the server needs to compute an extra MD5 hash, but
it is not noticeable in practice.
* In HEAD, modify CREATE and ALTER ROLE to clear the password if an empty
string, or a password hash that corresponds to an empty string, is
specified. The user-visible behavior is the same as in the stable branches,
the user cannot log in, but it seems better to stop the empty password from
entering the system in the first place. Secondly, it is fairly expensive to
check that a SCRAM hash doesn't correspond to an empty string, because
computing a SCRAM hash is much more expensive than an MD5 hash by design,
so better avoid doing that on every authentication.
We could clear the password on CREATE/ALTER ROLE also in stable branches,
but we would still need to check at authentication time, because even if we
prevent empty passwords from being stored in pg_authid, there might be
existing ones there already.
Reported by Jeroen van der Ham, Ben de Graaff and Jelte Fennema.
Security: CVE-2017-7546
2017-08-07 16:03:42 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't allow an empty password. Libpq treats an empty password the
|
|
|
|
* same as no password at all, and won't even try to authenticate. But
|
|
|
|
* other clients might, so allowing it would be confusing. By clearing
|
|
|
|
* the password when an empty string is specified, the account is
|
|
|
|
* consistently locked for all clients.
|
|
|
|
*
|
|
|
|
* Note that this only covers passwords stored in the database itself.
|
|
|
|
* There are also checks in the authentication code, to forbid an
|
|
|
|
* empty password from being used with authentication methods that
|
|
|
|
* fetch the password from an external system, like LDAP or PAM.
|
|
|
|
*/
|
|
|
|
if (password[0] == '\0' ||
|
|
|
|
plain_crypt_verify(stmt->role, password, "", &logdetail) == STATUS_OK)
|
|
|
|
{
|
|
|
|
ereport(NOTICE,
|
|
|
|
(errmsg("empty string is not a valid password, clearing password")));
|
|
|
|
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Encrypt the password to the requested format. */
|
|
|
|
shadow_pass = encrypt_password(Password_encryption, stmt->role,
|
|
|
|
password);
|
|
|
|
new_record[Anum_pg_authid_rolpassword - 1] =
|
|
|
|
CStringGetTextDatum(shadow_pass);
|
|
|
|
}
|
2001-08-15 20:42:16 +02:00
|
|
|
}
|
2002-04-27 23:24:34 +02:00
|
|
|
else
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
|
2002-04-27 23:24:34 +02:00
|
|
|
|
2009-11-18 22:57:56 +01:00
|
|
|
new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
|
|
|
|
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
|
|
|
|
|
2011-01-08 03:59:29 +01:00
|
|
|
/*
|
|
|
|
* pg_largeobject_metadata contains pg_authid.oid's, so we use the
|
2014-08-26 04:19:05 +02:00
|
|
|
* binary-upgrade override.
|
2011-01-08 03:59:29 +01:00
|
|
|
*/
|
2014-08-26 04:19:05 +02:00
|
|
|
if (IsBinaryUpgrade)
|
2011-01-08 03:59:29 +01:00
|
|
|
{
|
2014-08-26 04:19:05 +02:00
|
|
|
if (!OidIsValid(binary_upgrade_next_pg_authid_oid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("pg_authid OID value not set when in binary upgrade mode")));
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
roleid = binary_upgrade_next_pg_authid_oid;
|
2011-01-08 03:59:29 +01:00
|
|
|
binary_upgrade_next_pg_authid_oid = InvalidOid;
|
|
|
|
}
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
roleid = GetNewOidWithIndex(pg_authid_rel, AuthIdOidIndexId,
|
|
|
|
Anum_pg_authid_oid);
|
|
|
|
}
|
|
|
|
|
|
|
|
new_record[Anum_pg_authid_oid - 1] = ObjectIdGetDatum(roleid);
|
|
|
|
|
|
|
|
tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
|
2011-01-08 03:59:29 +01:00
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* Insert new record in the pg_authid table
|
2000-01-14 23:11:38 +01:00
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
CatalogTupleInsert(pg_authid_rel, tuple);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
/*
|
|
|
|
* Advance command counter so we can see new record; else tests in
|
|
|
|
* AddRoleMems may fail.
|
|
|
|
*/
|
|
|
|
if (addroleto || adminmembers || rolemembers)
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
/* Default grant. */
|
|
|
|
InitGrantRoleOptions(&popt);
|
|
|
|
|
1997-12-04 01:34:01 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* Add the new role to the specified existing roles.
|
1997-12-04 01:34:01 +01:00
|
|
|
*/
|
2020-04-25 06:09:30 +02:00
|
|
|
if (addroleto)
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
2020-04-25 06:09:30 +02:00
|
|
|
RoleSpec *thisrole = makeNode(RoleSpec);
|
|
|
|
List *thisrole_list = list_make1(thisrole);
|
|
|
|
List *thisrole_oidlist = list_make1_oid(roleid);
|
|
|
|
|
|
|
|
thisrole->roletype = ROLESPEC_CSTRING;
|
|
|
|
thisrole->rolename = stmt->role;
|
|
|
|
thisrole->location = -1;
|
2015-03-09 21:00:43 +01:00
|
|
|
|
2020-04-25 06:09:30 +02:00
|
|
|
foreach(item, addroleto)
|
|
|
|
{
|
|
|
|
RoleSpec *oldrole = lfirst(item);
|
|
|
|
HeapTuple oldroletup = get_rolespec_tuple(oldrole);
|
|
|
|
Form_pg_authid oldroleform = (Form_pg_authid) GETSTRUCT(oldroletup);
|
|
|
|
Oid oldroleid = oldroleform->oid;
|
|
|
|
char *oldrolename = NameStr(oldroleform->rolname);
|
|
|
|
|
2023-01-05 20:30:40 +01:00
|
|
|
/* can only add this role to roles for which you have rights */
|
2023-01-05 20:33:35 +01:00
|
|
|
check_role_membership_authorization(currentUserId, oldroleid, true);
|
|
|
|
AddRoleMems(currentUserId, oldrolename, oldroleid,
|
2020-04-25 06:09:30 +02:00
|
|
|
thisrole_list,
|
|
|
|
thisrole_oidlist,
|
2022-08-25 16:06:02 +02:00
|
|
|
InvalidOid, &popt);
|
2020-04-25 06:09:30 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(oldroletup);
|
|
|
|
}
|
1999-12-16 18:24:19 +01:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
/*
|
|
|
|
* If the current user isn't a superuser, make them an admin of the new
|
|
|
|
* role so that they can administer the new object they just created.
|
|
|
|
* Superusers will be able to do that anyway.
|
|
|
|
*
|
|
|
|
* The grantor of record for this implicit grant is the bootstrap
|
|
|
|
* superuser, which means that the CREATEROLE user cannot revoke the
|
2023-05-19 23:24:48 +02:00
|
|
|
* grant. They can however grant the created role back to themselves with
|
|
|
|
* different options, since they enjoy ADMIN OPTION on it.
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
*/
|
|
|
|
if (!superuser())
|
|
|
|
{
|
|
|
|
RoleSpec *current_role = makeNode(RoleSpec);
|
2023-01-10 18:44:49 +01:00
|
|
|
GrantRoleOptions poptself;
|
|
|
|
List *memberSpecs;
|
|
|
|
List *memberIds = list_make1_oid(currentUserId);
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
|
|
|
|
current_role->roletype = ROLESPEC_CURRENT_ROLE;
|
|
|
|
current_role->location = -1;
|
2023-01-10 18:44:49 +01:00
|
|
|
memberSpecs = list_make1(current_role);
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
|
|
|
|
poptself.specified = GRANT_ROLE_SPECIFIED_ADMIN
|
|
|
|
| GRANT_ROLE_SPECIFIED_INHERIT
|
|
|
|
| GRANT_ROLE_SPECIFIED_SET;
|
|
|
|
poptself.admin = true;
|
|
|
|
poptself.inherit = false;
|
|
|
|
poptself.set = false;
|
|
|
|
|
|
|
|
AddRoleMems(BOOTSTRAP_SUPERUSERID, stmt->role, roleid,
|
2023-01-10 18:44:49 +01:00
|
|
|
memberSpecs, memberIds,
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
BOOTSTRAP_SUPERUSERID, &poptself);
|
|
|
|
|
|
|
|
/*
|
2023-05-19 23:24:48 +02:00
|
|
|
* We must make the implicit grant visible to the code below, else the
|
|
|
|
* additional grants will fail.
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
2023-01-10 18:44:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Because of the implicit grant above, a CREATEROLE user who creates
|
|
|
|
* a role has the ability to grant that role back to themselves with
|
|
|
|
* the INHERIT or SET options, if they wish to inherit the role's
|
|
|
|
* privileges or be able to SET ROLE to it. The createrole_self_grant
|
|
|
|
* GUC can be used to make this happen automatically. This has no
|
|
|
|
* security implications since the same user is able to make the same
|
|
|
|
* grant using an explicit GRANT statement; it's just convenient.
|
|
|
|
*/
|
|
|
|
if (createrole_self_grant_enabled)
|
|
|
|
AddRoleMems(currentUserId, stmt->role, roleid,
|
|
|
|
memberSpecs, memberIds,
|
|
|
|
currentUserId, &createrole_self_grant_options);
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
}
|
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
/*
|
2005-06-28 21:51:26 +02:00
|
|
|
* Add the specified members to this new role. adminmembers get the admin
|
|
|
|
* option, rolemembers don't.
|
2023-01-05 20:30:40 +01:00
|
|
|
*
|
2023-05-19 23:24:48 +02:00
|
|
|
* NB: No permissions check is required here. If you have enough rights to
|
|
|
|
* create a role, you can add any members you like.
|
2005-06-28 07:09:14 +02:00
|
|
|
*/
|
2023-01-05 20:33:35 +01:00
|
|
|
AddRoleMems(currentUserId, stmt->role, roleid,
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
rolemembers, roleSpecsToIds(rolemembers),
|
2022-08-25 16:06:02 +02:00
|
|
|
InvalidOid, &popt);
|
|
|
|
popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN;
|
|
|
|
popt.admin = true;
|
2023-01-05 20:33:35 +01:00
|
|
|
AddRoleMems(currentUserId, stmt->role, roleid,
|
2022-08-25 16:06:02 +02:00
|
|
|
adminmembers, roleSpecsToIds(adminmembers),
|
|
|
|
InvalidOid, &popt);
|
2005-06-28 07:09:14 +02:00
|
|
|
|
2010-11-25 17:48:49 +01:00
|
|
|
/* Post creation hook for new role */
|
2013-03-07 02:52:06 +01:00
|
|
|
InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
|
2010-11-25 17:48:49 +01:00
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
/*
|
2009-09-01 04:54:52 +02:00
|
|
|
* Close pg_authid, but keep lock till commit.
|
1999-09-18 21:08:25 +02:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pg_authid_rel, NoLock);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
|
|
|
return roleid;
|
1997-12-04 01:34:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* ALTER ROLE
|
2005-07-27 00:37:50 +02:00
|
|
|
*
|
|
|
|
* Note: the rolemembers option accepted here is intended to support the
|
|
|
|
* backwards-compatible ALTER GROUP syntax. Although it will work to say
|
|
|
|
* "ALTER ROLE role ROLE rolenames", we don't document it.
|
2000-01-14 23:11:38 +01:00
|
|
|
*/
|
2012-12-29 13:55:37 +01:00
|
|
|
Oid
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
|
1997-12-04 01:34:01 +01:00
|
|
|
{
|
2022-07-16 08:42:15 +02:00
|
|
|
Datum new_record[Natts_pg_authid] = {0};
|
|
|
|
bool new_record_nulls[Natts_pg_authid] = {0};
|
|
|
|
bool new_record_repl[Natts_pg_authid] = {0};
|
2005-06-28 07:09:14 +02:00
|
|
|
Relation pg_authid_rel;
|
|
|
|
TupleDesc pg_authid_dsc;
|
2000-01-14 23:11:38 +01:00
|
|
|
HeapTuple tuple,
|
|
|
|
new_tuple;
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
Form_pg_authid authform;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *option;
|
2022-01-14 10:46:49 +01:00
|
|
|
char *rolename;
|
2005-06-28 07:09:14 +02:00
|
|
|
char *password = NULL; /* user password */
|
2005-07-31 19:19:22 +02:00
|
|
|
int connlimit = -1; /* maximum connections allowed */
|
2005-06-28 21:51:26 +02:00
|
|
|
char *validUntil = NULL; /* time the login is valid until */
|
2009-11-18 22:57:56 +01:00
|
|
|
Datum validUntil_datum; /* same, as timestamptz Datum */
|
|
|
|
bool validUntil_null;
|
2001-07-11 00:09:29 +02:00
|
|
|
DefElem *dpassword = NULL;
|
2005-06-29 22:34:15 +02:00
|
|
|
DefElem *dissuper = NULL;
|
2005-07-26 18:38:29 +02:00
|
|
|
DefElem *dinherit = NULL;
|
2005-06-28 07:09:14 +02:00
|
|
|
DefElem *dcreaterole = NULL;
|
2005-06-29 22:34:15 +02:00
|
|
|
DefElem *dcreatedb = NULL;
|
2005-06-28 07:09:14 +02:00
|
|
|
DefElem *dcanlogin = NULL;
|
2010-12-29 11:05:03 +01:00
|
|
|
DefElem *disreplication = NULL;
|
2005-07-31 19:19:22 +02:00
|
|
|
DefElem *dconnlimit = NULL;
|
2005-06-28 21:51:26 +02:00
|
|
|
DefElem *drolemembers = NULL;
|
2005-06-29 22:34:15 +02:00
|
|
|
DefElem *dvalidUntil = NULL;
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
DefElem *dbypassRLS = NULL;
|
2005-06-28 07:09:14 +02:00
|
|
|
Oid roleid;
|
2023-01-05 20:33:35 +01:00
|
|
|
Oid currentUserId = GetUserId();
|
2023-05-19 23:24:48 +02:00
|
|
|
GrantRoleOptions popt;
|
2001-07-11 00:09:29 +02:00
|
|
|
|
2016-04-08 22:56:27 +02:00
|
|
|
check_rolespec_name(stmt->role,
|
2022-09-28 17:14:53 +02:00
|
|
|
_("Cannot alter reserved roles."));
|
2016-04-08 22:56:27 +02:00
|
|
|
|
2001-07-11 00:09:29 +02:00
|
|
|
/* Extract options from the statement node tree */
|
|
|
|
foreach(option, stmt->options)
|
|
|
|
{
|
|
|
|
DefElem *defel = (DefElem *) lfirst(option);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
Remove support for password_encryption='off' / 'plain'.
Storing passwords in plaintext hasn't been a good idea for a very long
time, if ever. Now seems like a good time to finally forbid it, since we're
messing with this in PostgreSQL 10 anyway.
Remove the CREATE/ALTER USER UNENCRYPTED PASSSWORD 'foo' syntax, since
storing passwords unencrypted is no longer supported. ENCRYPTED PASSWORD
'foo' is still accepted, but ENCRYPTED is now just a noise-word, it does
the same as just PASSWORD 'foo'.
Likewise, remove the --unencrypted option from createuser, but accept
--encrypted as a no-op for backward compatibility. AFAICS, --encrypted was
a no-op even before this patch, because createuser encrypted the password
before sending it to the server even if --encrypted was not specified. It
added the ENCRYPTED keyword to the SQL command, but since the password was
already in encrypted form, it didn't make any difference. The documentation
was not clear on whether that was intended or not, but it's moot now.
Also, while password_encryption='on' is still accepted as an alias for
'md5', it is now marked as hidden, so that it is not listed as an accepted
value in error hints, for example. That's not directly related to removing
'plain', but it seems better this way.
Reviewed by Michael Paquier
Discussion: https://www.postgresql.org/message-id/16e9b768-fd78-0b12-cfc1-7b6b7f238fde@iki.fi
2017-05-08 10:26:07 +02:00
|
|
|
if (strcmp(defel->defname, "password") == 0)
|
2001-09-19 11:48:42 +02:00
|
|
|
{
|
2001-07-11 00:09:29 +02:00
|
|
|
if (dpassword)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2001-07-11 00:09:29 +02:00
|
|
|
dpassword = defel;
|
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
else if (strcmp(defel->defname, "superuser") == 0)
|
2001-09-19 11:48:42 +02:00
|
|
|
{
|
2005-06-29 22:34:15 +02:00
|
|
|
if (dissuper)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-29 22:34:15 +02:00
|
|
|
dissuper = defel;
|
2001-07-11 00:09:29 +02:00
|
|
|
}
|
2005-07-26 18:38:29 +02:00
|
|
|
else if (strcmp(defel->defname, "inherit") == 0)
|
|
|
|
{
|
|
|
|
if (dinherit)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-07-26 18:38:29 +02:00
|
|
|
dinherit = defel;
|
|
|
|
}
|
2005-06-28 07:09:14 +02:00
|
|
|
else if (strcmp(defel->defname, "createrole") == 0)
|
2001-09-19 11:48:42 +02:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
if (dcreaterole)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-28 07:09:14 +02:00
|
|
|
dcreaterole = defel;
|
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
else if (strcmp(defel->defname, "createdb") == 0)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
2005-06-29 22:34:15 +02:00
|
|
|
if (dcreatedb)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-29 22:34:15 +02:00
|
|
|
dcreatedb = defel;
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
else if (strcmp(defel->defname, "canlogin") == 0)
|
2001-09-19 11:48:42 +02:00
|
|
|
{
|
2005-06-29 22:34:15 +02:00
|
|
|
if (dcanlogin)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-29 22:34:15 +02:00
|
|
|
dcanlogin = defel;
|
2001-07-11 00:09:29 +02:00
|
|
|
}
|
2010-12-29 11:05:03 +01:00
|
|
|
else if (strcmp(defel->defname, "isreplication") == 0)
|
|
|
|
{
|
|
|
|
if (disreplication)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2010-12-29 11:05:03 +01:00
|
|
|
disreplication = defel;
|
|
|
|
}
|
2005-07-31 19:19:22 +02:00
|
|
|
else if (strcmp(defel->defname, "connectionlimit") == 0)
|
|
|
|
{
|
|
|
|
if (dconnlimit)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-07-31 19:19:22 +02:00
|
|
|
dconnlimit = defel;
|
|
|
|
}
|
2005-06-28 21:51:26 +02:00
|
|
|
else if (strcmp(defel->defname, "rolemembers") == 0 &&
|
|
|
|
stmt->action != 0)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
2005-06-28 21:51:26 +02:00
|
|
|
if (drolemembers)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-28 21:51:26 +02:00
|
|
|
drolemembers = defel;
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
else if (strcmp(defel->defname, "validUntil") == 0)
|
|
|
|
{
|
|
|
|
if (dvalidUntil)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
2005-06-29 22:34:15 +02:00
|
|
|
dvalidUntil = defel;
|
|
|
|
}
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
else if (strcmp(defel->defname, "bypassrls") == 0)
|
|
|
|
{
|
|
|
|
if (dbypassRLS)
|
Improve reporting of "conflicting or redundant options" errors.
When reporting "conflicting or redundant options" errors, try to
ensure that errposition() is used, to help the user identify the
offending option.
Formerly, errposition() was invoked in less than 60% of cases. This
patch raises that to over 90%, but there remain a few places where the
ParseState is not readily available. Using errdetail() might improve
the error in such cases, but that is left as a task for the future.
Additionally, since this error is thrown from over 100 places in the
codebase, introduce a dedicated function to throw it, reducing code
duplication.
Extracted from a slightly larger patch by Vignesh C. Reviewed by
Bharath Rupireddy, Alvaro Herrera, Dilip Kumar, Hou Zhijie, Peter
Smith, Daniel Gustafsson, Julien Rouhaud and me.
Discussion: https://postgr.es/m/CALDaNm33FFSS5tVyvmkoK2cCMuDVxcui=gFrjti9ROfynqSAGA@mail.gmail.com
2021-07-15 09:49:45 +02:00
|
|
|
errorConflictingDefElem(defel, pstate);
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
dbypassRLS = defel;
|
|
|
|
}
|
2001-08-15 20:42:16 +02:00
|
|
|
else
|
2003-07-19 01:20:33 +02:00
|
|
|
elog(ERROR, "option \"%s\" not recognized",
|
2001-07-11 00:09:29 +02:00
|
|
|
defel->defname);
|
|
|
|
}
|
2001-08-15 20:42:16 +02:00
|
|
|
|
2005-12-23 17:46:39 +01:00
|
|
|
if (dpassword && dpassword->arg)
|
2005-06-29 22:34:15 +02:00
|
|
|
password = strVal(dpassword->arg);
|
2005-07-31 19:19:22 +02:00
|
|
|
if (dconnlimit)
|
2009-01-30 18:24:47 +01:00
|
|
|
{
|
2005-07-31 19:19:22 +02:00
|
|
|
connlimit = intVal(dconnlimit->arg);
|
2009-01-30 18:24:47 +01:00
|
|
|
if (connlimit < -1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("invalid connection limit: %d", connlimit)));
|
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
if (dvalidUntil)
|
|
|
|
validUntil = strVal(dvalidUntil->arg);
|
2000-01-14 23:11:38 +01:00
|
|
|
|
1998-02-25 14:09:49 +01:00
|
|
|
/*
|
2006-05-04 18:07:29 +02:00
|
|
|
* Scan the pg_authid relation to be certain the user exists.
|
1997-12-04 01:34:01 +01:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
|
2005-06-28 07:09:14 +02:00
|
|
|
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
tuple = get_rolespec_tuple(stmt->role);
|
|
|
|
authform = (Form_pg_authid) GETSTRUCT(tuple);
|
|
|
|
rolename = pstrdup(NameStr(authform->rolname));
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
roleid = authform->oid;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
/* To mess with a superuser in any way you gotta be superuser. */
|
2023-03-17 10:14:16 +01:00
|
|
|
if (!superuser() && authform->rolsuper)
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute may alter roles with %s.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
|
|
|
if (!superuser() && dissuper)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute may change the %s attribute.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Most changes to a role require that you both have CREATEROLE privileges
|
|
|
|
* and also ADMIN OPTION on the role.
|
|
|
|
*/
|
|
|
|
if (!have_createrole_privilege() ||
|
|
|
|
!is_admin_of_role(GetUserId(), roleid))
|
2005-06-29 22:34:15 +02:00
|
|
|
{
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
/* things an unprivileged user certainly can't do */
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dinherit || dcreaterole || dcreatedb || dcanlogin || dconnlimit ||
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
dvalidUntil || disreplication || dbypassRLS)
|
2005-06-29 22:34:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
|
|
|
|
"CREATEROLE", "ADMIN", rolename)));
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
/* an unprivileged user can change their own password */
|
2023-01-05 20:33:35 +01:00
|
|
|
if (dpassword && roleid != currentUserId)
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("To change another role's password, the current user must have the %s attribute and the %s option on the role.",
|
|
|
|
"CREATEROLE", "ADMIN")));
|
2005-06-29 22:34:15 +02:00
|
|
|
}
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
else if (!superuser())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Even if you have both CREATEROLE and ADMIN OPTION on a role, you
|
|
|
|
* can only change the CREATEDB, REPLICATION, or BYPASSRLS attributes
|
|
|
|
* if they are set for your own role (or you are the superuser).
|
|
|
|
*/
|
|
|
|
if (dcreatedb && !have_createdb_privilege())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute may change the %s attribute.",
|
|
|
|
"CREATEDB", "CREATEDB")));
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (disreplication && !has_rolreplication(currentUserId))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute may change the %s attribute.",
|
|
|
|
"REPLICATION", "REPLICATION")));
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
if (dbypassRLS && !has_bypassrls_privilege(currentUserId))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute may change the %s attribute.",
|
|
|
|
"BYPASSRLS", "BYPASSRLS")));
|
Adjust interaction of CREATEROLE with role properties.
Previously, a CREATEROLE user without SUPERUSER could not alter
REPLICATION users in any way, and could not set the BYPASSRLS
attribute. However, they could manipulate the CREATEDB property
even if they themselves did not possess it.
With this change, a CREATEROLE user without SUPERUSER can set or
clear the REPLICATION, BYPASSRLS, or CREATEDB property on a new
role or a role that they have rights to manage if and only if
that property is set for their own role.
This implements the standard idea that you can't give permissions
you don't have (but you can give the ones you do have). We might
in the future want to provide more powerful ways to constrain
what a CREATEROLE user can do - for example, to limit whether
CONNECTION LIMIT can be set or the values to which it can be set -
but that is left as future work.
Patch by me, reviewed by Nathan Bossart, Tushar Ahuja, and Neha
Sharma.
Discussion: http://postgr.es/m/CA+TgmobX=LHg_J5aT=0pi9gJy=JdtrUVGAu0zhr-i5v5nNbJDg@mail.gmail.com
2023-01-24 16:57:09 +01:00
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
/* To add members to a role, you need ADMIN OPTION. */
|
|
|
|
if (drolemembers && !is_admin_of_role(currentUserId, roleid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s option on role \"%s\" may add members.",
|
|
|
|
"ADMIN", rolename)));
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
|
2009-11-18 22:57:56 +01:00
|
|
|
/* Convert validuntil to internal form */
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dvalidUntil)
|
2009-11-18 22:57:56 +01:00
|
|
|
{
|
|
|
|
validUntil_datum = DirectFunctionCall3(timestamptz_in,
|
|
|
|
CStringGetDatum(validUntil),
|
|
|
|
ObjectIdGetDatum(InvalidOid),
|
|
|
|
Int32GetDatum(-1));
|
|
|
|
validUntil_null = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* fetch existing setting in case hook needs it */
|
|
|
|
validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
|
|
|
|
Anum_pg_authid_rolvaliduntil,
|
|
|
|
&validUntil_null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Call the password checking hook if there is one defined
|
|
|
|
*/
|
|
|
|
if (check_password_hook && password)
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
(*check_password_hook) (rolename,
|
|
|
|
password,
|
Replace isMD5() with a more future-proof way to check if pw is encrypted.
The rule is that if pg_authid.rolpassword begins with "md5" and has the
right length, it's an MD5 hash, otherwise it's a plaintext password. The
idiom has been to use isMD5() to check for that, but that gets awkward,
when we add new kinds of verifiers, like the verifiers for SCRAM
authentication in the pending SCRAM patch set. Replace isMD5() with a new
get_password_type() function, so that when new verifier types are added, we
don't need to remember to modify every place that currently calls isMD5(),
to also recognize the new kinds of verifiers.
Also, use the new plain_crypt_verify function in passwordcheck, so that it
doesn't need to know about MD5, or in the future, about other kinds of
hashes or password verifiers.
Reviewed by Michael Paquier and Peter Eisentraut.
Discussion: https://www.postgresql.org/message-id/2d07165c-1793-e243-a2a9-e45b624c7580@iki.fi
2017-02-01 12:11:37 +01:00
|
|
|
get_password_type(password),
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
validUntil_datum,
|
|
|
|
validUntil_null);
|
2009-11-18 22:57:56 +01:00
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
2002-04-27 23:24:34 +02:00
|
|
|
* Build an updated tuple, perusing the information just obtained
|
2000-01-14 23:11:38 +01:00
|
|
|
*/
|
2002-04-27 23:24:34 +02:00
|
|
|
|
2001-09-08 17:24:00 +02:00
|
|
|
/*
|
2015-03-07 05:42:38 +01:00
|
|
|
* issuper/createrole/etc
|
2001-09-08 17:24:00 +02:00
|
|
|
*/
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dissuper)
|
1999-11-30 04:57:29 +01:00
|
|
|
{
|
2023-05-19 23:24:48 +02:00
|
|
|
bool should_be_super = boolVal(dissuper->arg);
|
2022-07-26 20:10:38 +02:00
|
|
|
|
|
|
|
if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
|
|
|
|
ereport(ERROR,
|
2023-03-17 10:14:16 +01:00
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("The bootstrap user must have the %s attribute.",
|
|
|
|
"SUPERUSER")));
|
2022-07-26 20:10:38 +02:00
|
|
|
|
2022-07-26 21:10:25 +02:00
|
|
|
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(should_be_super);
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dinherit)
|
2005-07-26 18:38:29 +02:00
|
|
|
{
|
2022-01-14 10:46:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(boolVal(dinherit->arg));
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
|
2005-07-26 18:38:29 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dcreaterole)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
2022-01-14 10:46:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(boolVal(dcreaterole->arg));
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dcreatedb)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
2022-01-14 10:46:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(boolVal(dcreatedb->arg));
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dcanlogin)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
2022-01-14 10:46:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(boolVal(dcanlogin->arg));
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
|
2000-01-14 23:11:38 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2022-01-14 10:46:49 +01:00
|
|
|
if (disreplication)
|
2010-12-29 11:05:03 +01:00
|
|
|
{
|
2022-01-14 10:46:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(boolVal(disreplication->arg));
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
|
2010-12-29 11:05:03 +01:00
|
|
|
}
|
|
|
|
|
2005-07-31 19:19:22 +02:00
|
|
|
if (dconnlimit)
|
|
|
|
{
|
|
|
|
new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
|
2005-07-31 19:19:22 +02:00
|
|
|
}
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/* password */
|
2001-07-11 00:09:29 +02:00
|
|
|
if (password)
|
1999-11-30 04:57:29 +01:00
|
|
|
{
|
Replace isMD5() with a more future-proof way to check if pw is encrypted.
The rule is that if pg_authid.rolpassword begins with "md5" and has the
right length, it's an MD5 hash, otherwise it's a plaintext password. The
idiom has been to use isMD5() to check for that, but that gets awkward,
when we add new kinds of verifiers, like the verifiers for SCRAM
authentication in the pending SCRAM patch set. Replace isMD5() with a new
get_password_type() function, so that when new verifier types are added, we
don't need to remember to modify every place that currently calls isMD5(),
to also recognize the new kinds of verifiers.
Also, use the new plain_crypt_verify function in passwordcheck, so that it
doesn't need to know about MD5, or in the future, about other kinds of
hashes or password verifiers.
Reviewed by Michael Paquier and Peter Eisentraut.
Discussion: https://www.postgresql.org/message-id/2d07165c-1793-e243-a2a9-e45b624c7580@iki.fi
2017-02-01 12:11:37 +01:00
|
|
|
char *shadow_pass;
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
const char *logdetail = NULL;
|
Replace isMD5() with a more future-proof way to check if pw is encrypted.
The rule is that if pg_authid.rolpassword begins with "md5" and has the
right length, it's an MD5 hash, otherwise it's a plaintext password. The
idiom has been to use isMD5() to check for that, but that gets awkward,
when we add new kinds of verifiers, like the verifiers for SCRAM
authentication in the pending SCRAM patch set. Replace isMD5() with a new
get_password_type() function, so that when new verifier types are added, we
don't need to remember to modify every place that currently calls isMD5(),
to also recognize the new kinds of verifiers.
Also, use the new plain_crypt_verify function in passwordcheck, so that it
doesn't need to know about MD5, or in the future, about other kinds of
hashes or password verifiers.
Reviewed by Michael Paquier and Peter Eisentraut.
Discussion: https://www.postgresql.org/message-id/2d07165c-1793-e243-a2a9-e45b624c7580@iki.fi
2017-02-01 12:11:37 +01:00
|
|
|
|
Don't allow logging in with empty password.
Some authentication methods allowed it, others did not. In the client-side,
libpq does not even try to authenticate with an empty password, which makes
using empty passwords hazardous: an administrator might think that an
account with an empty password cannot be used to log in, because psql
doesn't allow it, and not realize that a different client would in fact
allow it. To clear that confusion and to be be consistent, disallow empty
passwords in all authentication methods.
All the authentication methods that used plaintext authentication over the
wire, except for BSD authentication, already checked that the password
received from the user was not empty. To avoid forgetting it in the future
again, move the check to the recv_password_packet function. That only
forbids using an empty password with plaintext authentication, however.
MD5 and SCRAM need a different fix:
* In stable branches, check that the MD5 hash stored for the user does not
not correspond to an empty string. This adds some overhead to MD5
authentication, because the server needs to compute an extra MD5 hash, but
it is not noticeable in practice.
* In HEAD, modify CREATE and ALTER ROLE to clear the password if an empty
string, or a password hash that corresponds to an empty string, is
specified. The user-visible behavior is the same as in the stable branches,
the user cannot log in, but it seems better to stop the empty password from
entering the system in the first place. Secondly, it is fairly expensive to
check that a SCRAM hash doesn't correspond to an empty string, because
computing a SCRAM hash is much more expensive than an MD5 hash by design,
so better avoid doing that on every authentication.
We could clear the password on CREATE/ALTER ROLE also in stable branches,
but we would still need to check at authentication time, because even if we
prevent empty passwords from being stored in pg_authid, there might be
existing ones there already.
Reported by Jeroen van der Ham, Ben de Graaff and Jelte Fennema.
Security: CVE-2017-7546
2017-08-07 16:03:42 +02:00
|
|
|
/* Like in CREATE USER, don't allow an empty password. */
|
|
|
|
if (password[0] == '\0' ||
|
|
|
|
plain_crypt_verify(rolename, password, "", &logdetail) == STATUS_OK)
|
|
|
|
{
|
|
|
|
ereport(NOTICE,
|
|
|
|
(errmsg("empty string is not a valid password, clearing password")));
|
|
|
|
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Encrypt the password to the requested format. */
|
|
|
|
shadow_pass = encrypt_password(Password_encryption, rolename,
|
|
|
|
password);
|
|
|
|
new_record[Anum_pg_authid_rolpassword - 1] =
|
|
|
|
CStringGetTextDatum(shadow_pass);
|
|
|
|
}
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
|
1999-11-30 04:57:29 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2005-12-23 17:46:39 +01:00
|
|
|
/* unset password */
|
|
|
|
if (dpassword && dpassword->arg == NULL)
|
|
|
|
{
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
|
|
|
|
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
|
2005-12-23 17:46:39 +01:00
|
|
|
}
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/* valid until */
|
2009-11-18 22:57:56 +01:00
|
|
|
new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
|
|
|
|
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
|
|
|
|
new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
|
2002-03-01 23:45:19 +01:00
|
|
|
|
2022-01-14 10:46:49 +01:00
|
|
|
if (dbypassRLS)
|
2014-12-23 19:35:49 +01:00
|
|
|
{
|
2022-01-14 10:46:49 +01:00
|
|
|
new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(boolVal(dbypassRLS->arg));
|
2014-12-23 19:35:49 +01:00
|
|
|
new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
|
|
|
|
}
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
|
2002-04-27 23:24:34 +02:00
|
|
|
new_record_nulls, new_record_repl);
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
|
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
heap_freetuple(new_tuple);
|
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
InitGrantRoleOptions(&popt);
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
/*
|
2005-06-29 22:34:15 +02:00
|
|
|
* Advance command counter so we can see new record; else tests in
|
|
|
|
* AddRoleMems may fail.
|
1999-09-18 21:08:25 +02:00
|
|
|
*/
|
2022-01-14 10:46:49 +01:00
|
|
|
if (drolemembers)
|
|
|
|
{
|
|
|
|
List *rolemembers = (List *) drolemembers->arg;
|
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
CommandCounterIncrement();
|
2005-06-28 07:09:14 +02:00
|
|
|
|
2022-01-14 10:46:49 +01:00
|
|
|
if (stmt->action == +1) /* add members to role */
|
2023-01-05 20:33:35 +01:00
|
|
|
AddRoleMems(currentUserId, rolename, roleid,
|
2022-01-14 10:46:49 +01:00
|
|
|
rolemembers, roleSpecsToIds(rolemembers),
|
2022-08-25 16:06:02 +02:00
|
|
|
InvalidOid, &popt);
|
2022-01-14 10:46:49 +01:00
|
|
|
else if (stmt->action == -1) /* drop members from role */
|
2023-01-05 20:33:35 +01:00
|
|
|
DelRoleMems(currentUserId, rolename, roleid,
|
2022-01-14 10:46:49 +01:00
|
|
|
rolemembers, roleSpecsToIds(rolemembers),
|
2022-08-25 16:06:02 +02:00
|
|
|
InvalidOid, &popt, DROP_RESTRICT);
|
2022-01-14 10:46:49 +01:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
/*
|
2009-09-01 04:54:52 +02:00
|
|
|
* Close pg_authid, but keep lock till commit.
|
2005-06-29 22:34:15 +02:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pg_authid_rel, NoLock);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
|
|
|
return roleid;
|
1997-12-04 01:34:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-01 23:45:19 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* ALTER ROLE ... SET
|
2002-03-01 23:45:19 +01:00
|
|
|
*/
|
2012-12-29 13:55:37 +01:00
|
|
|
Oid
|
2005-06-28 07:09:14 +02:00
|
|
|
AlterRoleSet(AlterRoleSetStmt *stmt)
|
2002-03-01 23:45:19 +01:00
|
|
|
{
|
2009-10-08 00:14:26 +02:00
|
|
|
HeapTuple roletuple;
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
Form_pg_authid roleform;
|
2009-10-08 00:14:26 +02:00
|
|
|
Oid databaseid = InvalidOid;
|
2013-02-18 05:45:36 +01:00
|
|
|
Oid roleid = InvalidOid;
|
2009-10-08 00:14:26 +02:00
|
|
|
|
2013-02-18 05:45:36 +01:00
|
|
|
if (stmt->role)
|
2005-06-29 22:34:15 +02:00
|
|
|
{
|
2016-04-08 22:56:27 +02:00
|
|
|
check_rolespec_name(stmt->role,
|
2022-09-28 17:14:53 +02:00
|
|
|
_("Cannot alter reserved roles."));
|
2016-04-08 22:56:27 +02:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
roletuple = get_rolespec_tuple(stmt->role);
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
roleform = (Form_pg_authid) GETSTRUCT(roletuple);
|
|
|
|
roleid = roleform->oid;
|
2013-02-18 05:45:36 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Obtain a lock on the role and make sure it didn't go away in the
|
|
|
|
* meantime.
|
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
shdepLockAndCheckObject(AuthIdRelationId, roleid);
|
2013-02-18 05:45:36 +01:00
|
|
|
|
|
|
|
/*
|
2023-05-19 23:24:48 +02:00
|
|
|
* To mess with a superuser you gotta be superuser; otherwise you need
|
|
|
|
* CREATEROLE plus admin option on the target role; unless you're just
|
|
|
|
* trying to change your own settings
|
2013-02-18 05:45:36 +01:00
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
if (roleform->rolsuper)
|
2013-02-18 05:45:36 +01:00
|
|
|
{
|
|
|
|
if (!superuser())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute may alter roles with %s.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
2013-02-18 05:45:36 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
if ((!have_createrole_privilege() ||
|
2023-05-19 23:24:48 +02:00
|
|
|
!is_admin_of_role(GetUserId(), roleid))
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
&& roleid != GetUserId())
|
2013-02-18 05:45:36 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter role"),
|
|
|
|
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
|
2023-03-17 21:39:44 +01:00
|
|
|
"CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
|
2013-02-18 05:45:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSysCache(roletuple);
|
2005-06-29 22:34:15 +02:00
|
|
|
}
|
2002-03-01 23:45:19 +01:00
|
|
|
|
2009-10-08 00:14:26 +02:00
|
|
|
/* look up and lock the database, if specified */
|
|
|
|
if (stmt->database != NULL)
|
2002-03-01 23:45:19 +01:00
|
|
|
{
|
2010-08-05 16:45:09 +02:00
|
|
|
databaseid = get_database_oid(stmt->database, false);
|
2009-10-08 00:14:26 +02:00
|
|
|
shdepLockAndCheckObject(DatabaseRelationId, databaseid);
|
2013-02-18 05:45:36 +01:00
|
|
|
|
|
|
|
if (!stmt->role)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If no role is specified, then this is effectively the same as
|
|
|
|
* ALTER DATABASE ... SET, so use the same permission check.
|
|
|
|
*/
|
2022-11-13 08:11:17 +01:00
|
|
|
if (!object_ownercheck(DatabaseRelationId, databaseid, GetUserId()))
|
2017-12-02 15:26:34 +01:00
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
|
2013-02-18 05:45:36 +01:00
|
|
|
stmt->database);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!stmt->role && !stmt->database)
|
|
|
|
{
|
|
|
|
/* Must be superuser to alter settings globally. */
|
|
|
|
if (!superuser())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to alter setting"),
|
|
|
|
errdetail("Only roles with the %s attribute may alter settings globally.",
|
|
|
|
"SUPERUSER")));
|
2002-03-01 23:45:19 +01:00
|
|
|
}
|
|
|
|
|
2013-02-18 05:45:36 +01:00
|
|
|
AlterSetting(databaseid, roleid, stmt->setstmt);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
|
|
|
return roleid;
|
2002-03-01 23:45:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* DROP ROLE
|
2000-01-14 23:11:38 +01:00
|
|
|
*/
|
|
|
|
void
|
2005-06-28 07:09:14 +02:00
|
|
|
DropRole(DropRoleStmt *stmt)
|
1997-12-04 01:34:01 +01:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
Relation pg_authid_rel,
|
|
|
|
pg_auth_members_rel;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *item;
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
List *role_addresses = NIL;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2014-12-23 19:35:49 +01:00
|
|
|
if (!have_createrole_privilege())
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to drop role"),
|
|
|
|
errdetail("Only roles with the %s attribute and the %s option on the target roles may drop roles.",
|
|
|
|
"CREATEROLE", "ADMIN")));
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1998-02-25 14:09:49 +01:00
|
|
|
/*
|
2005-06-29 22:34:15 +02:00
|
|
|
* Scan the pg_authid relation to find the Oid of the role(s) to be
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
* deleted and perform preliminary permissions and sanity checks.
|
1997-12-04 01:34:01 +01:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
|
|
|
|
pg_auth_members_rel = table_open(AuthMemRelationId, RowExclusiveLock);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
foreach(item, stmt->roles)
|
2000-01-14 23:11:38 +01:00
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
RoleSpec *rolspec = lfirst(item);
|
|
|
|
char *role;
|
2000-01-14 23:11:38 +01:00
|
|
|
HeapTuple tuple,
|
|
|
|
tmp_tuple;
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
Form_pg_authid roleform;
|
2005-07-07 22:40:02 +02:00
|
|
|
ScanKeyData scankey;
|
2005-06-29 22:34:15 +02:00
|
|
|
SysScanDesc sscan;
|
2005-06-28 07:09:14 +02:00
|
|
|
Oid roleid;
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
ObjectAddress *role_address;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
if (rolspec->roletype != ROLESPEC_CSTRING)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2015-12-11 04:05:27 +01:00
|
|
|
errmsg("cannot use special role specifier in DROP ROLE")));
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
role = rolspec->rolename;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
|
2000-01-14 23:11:38 +01:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2006-02-04 20:06:47 +01:00
|
|
|
{
|
|
|
|
if (!stmt->missing_ok)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("role \"%s\" does not exist", role)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(NOTICE,
|
|
|
|
(errmsg("role \"%s\" does not exist, skipping",
|
|
|
|
role)));
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
roleform = (Form_pg_authid) GETSTRUCT(tuple);
|
|
|
|
roleid = roleform->oid;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
if (roleid == GetUserId())
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_IN_USE),
|
2005-07-26 00:12:34 +02:00
|
|
|
errmsg("current user cannot be dropped")));
|
|
|
|
if (roleid == GetOuterUserId())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_IN_USE),
|
|
|
|
errmsg("current user cannot be dropped")));
|
2005-06-28 07:09:14 +02:00
|
|
|
if (roleid == GetSessionUserId())
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_IN_USE),
|
2005-07-26 00:12:34 +02:00
|
|
|
errmsg("session user cannot be dropped")));
|
2001-09-08 17:24:00 +02:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
/*
|
|
|
|
* For safety's sake, we allow createrole holders to drop ordinary
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
* roles but not superuser roles, and only if they also have ADMIN
|
|
|
|
* OPTION.
|
2005-06-29 22:34:15 +02:00
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
if (roleform->rolsuper && !superuser())
|
2005-06-29 22:34:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to drop role"),
|
|
|
|
errdetail("Only roles with the %s attribute may drop roles with %s.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
if (!is_admin_of_role(GetUserId(), roleid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to drop role"),
|
|
|
|
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may drop this role.",
|
|
|
|
"CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
|
2005-06-29 22:34:15 +02:00
|
|
|
|
2012-03-09 20:34:56 +01:00
|
|
|
/* DROP hook for the role being removed */
|
2013-03-07 02:52:06 +01:00
|
|
|
InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
|
2012-03-09 20:34:56 +01:00
|
|
|
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
/* Don't leak the syscache tuple */
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
2005-07-07 22:40:02 +02:00
|
|
|
* Lock the role, so nobody can add dependencies to her while we drop
|
|
|
|
* her. We keep the lock until the end of transaction.
|
|
|
|
*/
|
|
|
|
LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
* If there is a pg_auth_members entry that has one of the roles to be
|
|
|
|
* dropped as the roleid or member, it should be silently removed, but
|
|
|
|
* if there is a pg_auth_members entry that has one of the roles to be
|
|
|
|
* dropped as the grantor, the operation should fail.
|
|
|
|
*
|
|
|
|
* It's possible, however, that a single pg_auth_members entry could
|
|
|
|
* fall into multiple categories - e.g. the user could do "GRANT foo
|
|
|
|
* TO bar GRANTED BY baz" and then "DROP ROLE baz, bar". We want such
|
|
|
|
* an operation to succeed regardless of the order in which the
|
|
|
|
* to-be-dropped roles are passed to DROP ROLE.
|
2000-01-14 23:11:38 +01:00
|
|
|
*
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
* To make that work, we remove all pg_auth_members entries that can
|
|
|
|
* be silently removed in this loop, and then below we'll make a
|
|
|
|
* second pass over the list of roles to be removed and check for any
|
|
|
|
* remaining dependencies.
|
2000-01-14 23:11:38 +01:00
|
|
|
*/
|
2005-06-29 22:34:15 +02:00
|
|
|
ScanKeyInit(&scankey,
|
|
|
|
Anum_pg_auth_members_roleid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(roleid));
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
true, NULL, 1, &scankey);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
|
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
|
|
|
|
deleteSharedDependencyRecordsFor(AuthMemRelationId,
|
|
|
|
authmem_form->oid, 0);
|
2017-02-01 22:13:30 +01:00
|
|
|
CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
|
2000-01-14 23:11:38 +01:00
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
systable_endscan(sscan);
|
2005-06-28 07:09:14 +02:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
ScanKeyInit(&scankey,
|
|
|
|
Anum_pg_auth_members_member,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(roleid));
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
true, NULL, 1, &scankey);
|
2005-06-29 22:34:15 +02:00
|
|
|
|
|
|
|
while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
|
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
|
|
|
|
deleteSharedDependencyRecordsFor(AuthMemRelationId,
|
|
|
|
authmem_form->oid, 0);
|
2017-02-01 22:13:30 +01:00
|
|
|
CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
|
|
|
|
systable_endscan(sscan);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Advance command counter so that later iterations of this loop will
|
|
|
|
* see the changes already made. This is essential if, for example,
|
|
|
|
* we are trying to drop both a role and one of its direct members ---
|
|
|
|
* we'll get an error if we try to delete the linking pg_auth_members
|
|
|
|
* tuple twice. (We do not need a CCI between the two delete loops
|
|
|
|
* above, because it's not allowed for a role to directly contain
|
|
|
|
* itself.)
|
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
|
|
|
|
/* Looks tentatively OK, add it to the list. */
|
|
|
|
role_address = palloc(sizeof(ObjectAddress));
|
|
|
|
role_address->classId = AuthIdRelationId;
|
|
|
|
role_address->objectId = roleid;
|
|
|
|
role_address->objectSubId = 0;
|
|
|
|
role_addresses = lappend(role_addresses, role_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Second pass over the roles to be removed.
|
|
|
|
*/
|
|
|
|
foreach(item, role_addresses)
|
|
|
|
{
|
|
|
|
ObjectAddress *role_address = lfirst(item);
|
|
|
|
Oid roleid = role_address->objectId;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Form_pg_authid roleform;
|
|
|
|
char *detail;
|
|
|
|
char *detail_log;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Re-find the pg_authid tuple.
|
|
|
|
*
|
|
|
|
* Since we've taken a lock on the role OID, it shouldn't be possible
|
|
|
|
* for the tuple to have been deleted -- or for that matter updated --
|
|
|
|
* unless the user is manually modifying the system catalogs.
|
|
|
|
*/
|
|
|
|
tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "could not find tuple for role %u", roleid);
|
|
|
|
roleform = (Form_pg_authid) GETSTRUCT(tuple);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for pg_shdepend entries depending on this role.
|
|
|
|
*
|
|
|
|
* This needs to happen after we've completed removing any
|
|
|
|
* pg_auth_members entries that can be removed silently, in order to
|
|
|
|
* avoid spurious failures. See notes above for more details.
|
|
|
|
*/
|
|
|
|
if (checkSharedDependencies(AuthIdRelationId, roleid,
|
|
|
|
&detail, &detail_log))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
|
|
|
errmsg("role \"%s\" cannot be dropped because some objects depend on it",
|
|
|
|
NameStr(roleform->rolname)),
|
|
|
|
errdetail_internal("%s", detail),
|
|
|
|
errdetail_log("%s", detail_log)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove the role from the pg_authid table
|
|
|
|
*/
|
|
|
|
CatalogTupleDelete(pg_authid_rel, &tuple->t_self);
|
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove any comments or security labels on this role.
|
|
|
|
*/
|
|
|
|
DeleteSharedComments(roleid, AuthIdRelationId);
|
|
|
|
DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove settings for this role.
|
|
|
|
*/
|
|
|
|
DropSetting(InvalidOid, roleid);
|
2000-01-14 23:11:38 +01:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
/*
|
2009-09-01 04:54:52 +02:00
|
|
|
* Now we can clean up; but keep locks until commit.
|
1999-09-18 21:08:25 +02:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pg_auth_members_rel, NoLock);
|
|
|
|
table_close(pg_authid_rel, NoLock);
|
1997-12-04 01:34:01 +01:00
|
|
|
}
|
1998-02-19 18:20:01 +01:00
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* Rename role
|
2003-06-27 16:45:32 +02:00
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2005-06-28 07:09:14 +02:00
|
|
|
RenameRole(const char *oldname, const char *newname)
|
2003-06-27 16:45:32 +02:00
|
|
|
{
|
2004-05-06 18:59:16 +02:00
|
|
|
HeapTuple oldtuple,
|
|
|
|
newtuple;
|
|
|
|
TupleDesc dsc;
|
2003-06-27 16:45:32 +02:00
|
|
|
Relation rel;
|
2004-05-06 18:59:16 +02:00
|
|
|
Datum datum;
|
|
|
|
bool isnull;
|
2005-06-28 07:09:14 +02:00
|
|
|
Datum repl_val[Natts_pg_authid];
|
2008-11-02 02:45:28 +01:00
|
|
|
bool repl_null[Natts_pg_authid];
|
|
|
|
bool repl_repl[Natts_pg_authid];
|
2004-05-06 18:59:16 +02:00
|
|
|
int i;
|
2005-06-28 07:09:14 +02:00
|
|
|
Oid roleid;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2016-04-08 22:56:27 +02:00
|
|
|
Form_pg_authid authform;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_open(AuthIdRelationId, RowExclusiveLock);
|
2004-05-06 18:59:16 +02:00
|
|
|
dsc = RelationGetDescr(rel);
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
|
2004-05-06 18:59:16 +02:00
|
|
|
if (!HeapTupleIsValid(oldtuple))
|
2003-06-27 16:45:32 +02:00
|
|
|
ereport(ERROR,
|
2003-07-19 01:20:33 +02:00
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
2005-06-28 07:09:14 +02:00
|
|
|
errmsg("role \"%s\" does not exist", oldname)));
|
2003-06-27 16:45:32 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX Client applications probably store the session user somewhere, so
|
|
|
|
* renaming it could cause confusion. On the other hand, there may not be
|
|
|
|
* an actual problem besides a little confusion, so think about this and
|
2005-07-26 00:12:34 +02:00
|
|
|
* decide. Same for SET ROLE ... we don't restrict renaming the current
|
|
|
|
* effective userid, though.
|
2003-06-27 16:45:32 +02:00
|
|
|
*/
|
2005-06-28 07:09:14 +02:00
|
|
|
|
2016-04-08 22:56:27 +02:00
|
|
|
authform = (Form_pg_authid) GETSTRUCT(oldtuple);
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
roleid = authform->oid;
|
2005-06-28 07:09:14 +02:00
|
|
|
|
|
|
|
if (roleid == GetSessionUserId())
|
2003-06-27 16:45:32 +02:00
|
|
|
ereport(ERROR,
|
2003-07-19 01:20:33 +02:00
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
Wording cleanup for error messages. Also change can't -> cannot.
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
2007-02-01 20:10:30 +01:00
|
|
|
errmsg("session user cannot be renamed")));
|
2005-07-26 00:12:34 +02:00
|
|
|
if (roleid == GetOuterUserId())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
Wording cleanup for error messages. Also change can't -> cannot.
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
2007-02-01 20:10:30 +01:00
|
|
|
errmsg("current user cannot be renamed")));
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2016-04-08 22:56:27 +02:00
|
|
|
/*
|
|
|
|
* Check that the user is not trying to rename a system role and not
|
|
|
|
* trying to rename a role into the reserved "pg_" namespace.
|
|
|
|
*/
|
|
|
|
if (IsReservedName(NameStr(authform->rolname)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_RESERVED_NAME),
|
|
|
|
errmsg("role name \"%s\" is reserved",
|
|
|
|
NameStr(authform->rolname)),
|
|
|
|
errdetail("Role names starting with \"pg_\" are reserved.")));
|
|
|
|
|
|
|
|
if (IsReservedName(newname))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_RESERVED_NAME),
|
|
|
|
errmsg("role name \"%s\" is reserved",
|
|
|
|
newname),
|
|
|
|
errdetail("Role names starting with \"pg_\" are reserved.")));
|
|
|
|
|
Add an enforcement mechanism for global object names in regression tests.
In commit 18555b132 we tentatively established a rule that regression
tests should use names containing "regression" for databases, and names
starting with "regress_" for all other globally-visible object names, so
as to circumscribe the side-effects that "make installcheck" could have
on an existing installation.
This commit adds a simple enforcement mechanism for that rule: if the code
is compiled with ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS defined, it
will emit a warning (not an error) whenever a database, role, tablespace,
subscription, or replication origin name is created that doesn't obey the
rule. Running one or more buildfarm members with that symbol defined
should be enough to catch new violations, at least in the regular
regression tests. Most TAP tests wouldn't notice such warnings, but
that's actually fine because TAP tests don't execute against an existing
server anyway.
Since it's already the case that running src/test/modules/ tests in
installcheck mode is deprecated, we can use that as a home for tests
that seem unsafe to run against an existing server, such as tests that
might have side-effects on existing roles. Document that (though this
commit doesn't in itself make it any less safe than before).
Update regress.sgml to define these restrictions more clearly, and
to clean up assorted lack-of-up-to-date-ness in its descriptions of
the available regression tests.
Discussion: https://postgr.es/m/16638.1468620817@sss.pgh.pa.us
2019-06-29 17:34:00 +02:00
|
|
|
/*
|
|
|
|
* If built with appropriate switch, whine when regression-testing
|
|
|
|
* conventions for role names are violated.
|
|
|
|
*/
|
|
|
|
#ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
|
|
|
|
if (strncmp(newname, "regress_", 8) != 0)
|
|
|
|
elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
|
|
|
|
#endif
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
/* make sure the new name doesn't exist */
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
|
2003-06-27 16:45:32 +02:00
|
|
|
ereport(ERROR,
|
2003-07-19 01:20:33 +02:00
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
2005-06-28 07:09:14 +02:00
|
|
|
errmsg("role \"%s\" already exists", newname)));
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
/*
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
* Only superusers can mess with superusers. Otherwise, a user with
|
|
|
|
* CREATEROLE can rename a role for which they have ADMIN OPTION.
|
2005-06-29 22:34:15 +02:00
|
|
|
*/
|
2023-03-16 15:33:43 +01:00
|
|
|
if (authform->rolsuper)
|
2005-06-29 22:34:15 +02:00
|
|
|
{
|
|
|
|
if (!superuser())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to rename role"),
|
|
|
|
errdetail("Only roles with the %s attribute may rename roles with %s.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
2005-06-29 22:34:15 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
if (!have_createrole_privilege() ||
|
|
|
|
!is_admin_of_role(GetUserId(), roleid))
|
2005-06-29 22:34:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to rename role"),
|
|
|
|
errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may rename this role.",
|
|
|
|
"CREATEROLE", "ADMIN", NameStr(authform->rolname))));
|
2005-06-29 22:34:15 +02:00
|
|
|
}
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
/* OK, construct the modified tuple */
|
2005-06-28 07:09:14 +02:00
|
|
|
for (i = 0; i < Natts_pg_authid; i++)
|
2008-11-02 02:45:28 +01:00
|
|
|
repl_repl[i] = false;
|
2004-05-06 18:59:16 +02:00
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
repl_repl[Anum_pg_authid_rolname - 1] = true;
|
2005-06-28 07:09:14 +02:00
|
|
|
repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
|
2004-05-06 18:59:16 +02:00
|
|
|
CStringGetDatum(newname));
|
2008-11-02 02:45:28 +01:00
|
|
|
repl_null[Anum_pg_authid_rolname - 1] = false;
|
2004-05-06 18:59:16 +02:00
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
|
2004-05-06 18:59:16 +02:00
|
|
|
|
Replace isMD5() with a more future-proof way to check if pw is encrypted.
The rule is that if pg_authid.rolpassword begins with "md5" and has the
right length, it's an MD5 hash, otherwise it's a plaintext password. The
idiom has been to use isMD5() to check for that, but that gets awkward,
when we add new kinds of verifiers, like the verifiers for SCRAM
authentication in the pending SCRAM patch set. Replace isMD5() with a new
get_password_type() function, so that when new verifier types are added, we
don't need to remember to modify every place that currently calls isMD5(),
to also recognize the new kinds of verifiers.
Also, use the new plain_crypt_verify function in passwordcheck, so that it
doesn't need to know about MD5, or in the future, about other kinds of
hashes or password verifiers.
Reviewed by Michael Paquier and Peter Eisentraut.
Discussion: https://www.postgresql.org/message-id/2d07165c-1793-e243-a2a9-e45b624c7580@iki.fi
2017-02-01 12:11:37 +01:00
|
|
|
if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
|
2004-05-06 18:59:16 +02:00
|
|
|
{
|
|
|
|
/* MD5 uses the username as salt, so just clear it on a rename */
|
2008-11-02 02:45:28 +01:00
|
|
|
repl_repl[Anum_pg_authid_rolpassword - 1] = true;
|
|
|
|
repl_null[Anum_pg_authid_rolpassword - 1] = true;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-05-06 18:59:16 +02:00
|
|
|
ereport(NOTICE,
|
2005-06-28 07:09:14 +02:00
|
|
|
(errmsg("MD5 password cleared because of role rename")));
|
2004-05-06 18:59:16 +02:00
|
|
|
}
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, AuthIdRelationId, roleid);
|
|
|
|
|
2004-05-06 18:59:16 +02:00
|
|
|
ReleaseSysCache(oldtuple);
|
2006-05-04 18:07:29 +02:00
|
|
|
|
|
|
|
/*
|
2009-09-01 04:54:52 +02:00
|
|
|
* Close pg_authid, but keep lock till commit.
|
2006-05-04 18:07:29 +02:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, NoLock);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2003-06-27 16:45:32 +02:00
|
|
|
}
|
|
|
|
|
1998-02-19 18:20:01 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* GrantRoleStmt
|
1998-02-19 18:20:01 +01:00
|
|
|
*
|
2005-06-28 07:09:14 +02:00
|
|
|
* Grant/Revoke roles to/from roles
|
2000-01-14 23:11:38 +01:00
|
|
|
*/
|
1999-12-16 18:24:19 +01:00
|
|
|
void
|
2022-08-25 16:06:02 +02:00
|
|
|
GrantRole(ParseState *pstate, GrantRoleStmt *stmt)
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
2005-06-29 22:34:15 +02:00
|
|
|
Relation pg_authid_rel;
|
2005-06-28 07:09:14 +02:00
|
|
|
Oid grantor;
|
|
|
|
List *grantee_ids;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *item;
|
2023-05-19 23:24:48 +02:00
|
|
|
GrantRoleOptions popt;
|
2023-01-05 20:33:35 +01:00
|
|
|
Oid currentUserId = GetUserId();
|
2022-08-25 16:06:02 +02:00
|
|
|
|
|
|
|
/* Parse options list. */
|
|
|
|
InitGrantRoleOptions(&popt);
|
|
|
|
foreach(item, stmt->opt)
|
|
|
|
{
|
2023-05-19 23:24:48 +02:00
|
|
|
DefElem *opt = (DefElem *) lfirst(item);
|
2022-08-25 16:06:02 +02:00
|
|
|
char *optval = defGetString(opt);
|
|
|
|
|
|
|
|
if (strcmp(opt->defname, "admin") == 0)
|
|
|
|
{
|
|
|
|
popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN;
|
|
|
|
|
|
|
|
if (parse_bool(optval, &popt.admin))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (strcmp(opt->defname, "inherit") == 0)
|
|
|
|
{
|
|
|
|
popt.specified |= GRANT_ROLE_SPECIFIED_INHERIT;
|
|
|
|
if (parse_bool(optval, &popt.inherit))
|
|
|
|
continue;
|
|
|
|
}
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
else if (strcmp(opt->defname, "set") == 0)
|
|
|
|
{
|
|
|
|
popt.specified |= GRANT_ROLE_SPECIFIED_SET;
|
|
|
|
if (parse_bool(optval, &popt.set))
|
|
|
|
continue;
|
|
|
|
}
|
2022-08-25 16:06:02 +02:00
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("unrecognized role option \"%s\"", opt->defname),
|
|
|
|
parser_errposition(pstate, opt->location));
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("unrecognized value for role option \"%s\": \"%s\"",
|
|
|
|
opt->defname, optval),
|
|
|
|
parser_errposition(pstate, opt->location)));
|
|
|
|
}
|
2001-07-12 20:03:00 +02:00
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
/* Lookup OID of grantor, if specified. */
|
2005-06-28 07:09:14 +02:00
|
|
|
if (stmt->grantor)
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
grantor = get_rolespec_oid(stmt->grantor, false);
|
2005-06-28 07:09:14 +02:00
|
|
|
else
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
grantor = InvalidOid;
|
2001-07-12 20:03:00 +02:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
grantee_ids = roleSpecsToIds(stmt->grantee_roles);
|
1999-12-16 18:24:19 +01:00
|
|
|
|
2006-05-04 18:07:29 +02:00
|
|
|
/* AccessShareLock is enough since we aren't modifying pg_authid */
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_authid_rel = table_open(AuthIdRelationId, AccessShareLock);
|
2005-06-29 22:34:15 +02:00
|
|
|
|
1999-12-16 18:24:19 +01:00
|
|
|
/*
|
2022-08-25 16:06:02 +02:00
|
|
|
* Step through all of the granted roles and add, update, or remove
|
|
|
|
* entries in pg_auth_members as appropriate. If stmt->is_grant is true,
|
2023-05-19 23:24:48 +02:00
|
|
|
* we are adding new grants or, if they already exist, updating options on
|
|
|
|
* those grants. If stmt->is_grant is false, we are revoking grants or
|
2022-08-25 16:06:02 +02:00
|
|
|
* removing options from them.
|
2002-10-21 21:46:45 +02:00
|
|
|
*/
|
2005-06-28 07:09:14 +02:00
|
|
|
foreach(item, stmt->granted_roles)
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
2009-01-22 21:16:10 +01:00
|
|
|
AccessPriv *priv = (AccessPriv *) lfirst(item);
|
|
|
|
char *rolename = priv->priv_name;
|
|
|
|
Oid roleid;
|
|
|
|
|
|
|
|
/* Must reject priv(columns) and ALL PRIVILEGES(columns) */
|
|
|
|
if (rolename == NULL || priv->cols != NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
|
|
|
errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
|
1999-12-16 18:24:19 +01:00
|
|
|
|
2010-08-05 16:45:09 +02:00
|
|
|
roleid = get_role_oid(rolename, false);
|
2023-01-05 20:33:35 +01:00
|
|
|
check_role_membership_authorization(currentUserId,
|
|
|
|
roleid, stmt->is_grant);
|
2005-06-28 07:09:14 +02:00
|
|
|
if (stmt->is_grant)
|
2023-01-05 20:33:35 +01:00
|
|
|
AddRoleMems(currentUserId, rolename, roleid,
|
2005-06-28 07:09:14 +02:00
|
|
|
stmt->grantee_roles, grantee_ids,
|
2022-08-25 16:06:02 +02:00
|
|
|
grantor, &popt);
|
1999-12-16 18:24:19 +01:00
|
|
|
else
|
2023-01-05 20:33:35 +01:00
|
|
|
DelRoleMems(currentUserId, rolename, roleid,
|
2005-06-28 07:09:14 +02:00
|
|
|
stmt->grantee_roles, grantee_ids,
|
2022-08-25 16:06:02 +02:00
|
|
|
grantor, &popt, stmt->behavior);
|
1999-12-16 18:24:19 +01:00
|
|
|
}
|
2005-06-29 00:16:45 +02:00
|
|
|
|
2006-05-04 18:07:29 +02:00
|
|
|
/*
|
2009-09-01 04:54:52 +02:00
|
|
|
* Close pg_authid, but keep lock till commit.
|
2006-05-04 18:07:29 +02:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pg_authid_rel, NoLock);
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
1999-12-16 18:24:19 +01:00
|
|
|
|
2005-11-21 13:49:33 +01:00
|
|
|
/*
|
|
|
|
* DropOwnedObjects
|
|
|
|
*
|
|
|
|
* Drop the objects owned by a given list of roles.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
DropOwnedObjects(DropOwnedStmt *stmt)
|
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
List *role_ids = roleSpecsToIds(stmt->roles);
|
2005-11-21 13:49:33 +01:00
|
|
|
ListCell *cell;
|
|
|
|
|
|
|
|
/* Check privileges */
|
|
|
|
foreach(cell, role_ids)
|
|
|
|
{
|
|
|
|
Oid roleid = lfirst_oid(cell);
|
|
|
|
|
|
|
|
if (!has_privs_of_role(GetUserId(), roleid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to drop objects"),
|
|
|
|
errdetail("Only roles with privileges of role \"%s\" may drop objects owned by it.",
|
|
|
|
GetUserNameFromId(roleid, false))));
|
2005-11-21 13:49:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Ok, do it */
|
|
|
|
shdepDropOwned(role_ids, stmt->behavior);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ReassignOwnedObjects
|
|
|
|
*
|
|
|
|
* Give the objects owned by a given list of roles away to another user.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
|
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
List *role_ids = roleSpecsToIds(stmt->roles);
|
2005-11-21 13:49:33 +01:00
|
|
|
ListCell *cell;
|
|
|
|
Oid newrole;
|
|
|
|
|
|
|
|
/* Check privileges */
|
|
|
|
foreach(cell, role_ids)
|
|
|
|
{
|
|
|
|
Oid roleid = lfirst_oid(cell);
|
|
|
|
|
|
|
|
if (!has_privs_of_role(GetUserId(), roleid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to reassign objects"),
|
|
|
|
errdetail("Only roles with privileges of role \"%s\" may reassign objects owned by it.",
|
|
|
|
GetUserNameFromId(roleid, false))));
|
2005-11-21 13:49:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Must have privileges on the receiving side too */
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
newrole = get_rolespec_oid(stmt->newrole, false);
|
2005-11-21 13:49:33 +01:00
|
|
|
|
|
|
|
if (!has_privs_of_role(GetUserId(), newrole))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to reassign objects"),
|
|
|
|
errdetail("Only roles with privileges of role \"%s\" may reassign objects to it.",
|
|
|
|
GetUserNameFromId(newrole, false))));
|
2005-11-21 13:49:33 +01:00
|
|
|
|
|
|
|
/* Ok, do it */
|
|
|
|
shdepReassignOwned(role_ids, newrole);
|
|
|
|
}
|
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
/*
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
* roleSpecsToIds
|
|
|
|
*
|
|
|
|
* Given a list of RoleSpecs, generate a list of role OIDs in the same order.
|
2005-06-28 07:09:14 +02:00
|
|
|
*
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
* ROLESPEC_PUBLIC is not allowed.
|
2005-06-28 07:09:14 +02:00
|
|
|
*/
|
2014-01-24 05:52:40 +01:00
|
|
|
List *
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
roleSpecsToIds(List *memberNames)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
ListCell *l;
|
2002-04-27 23:24:34 +02:00
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
foreach(l, memberNames)
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
RoleSpec *rolespec = lfirst_node(RoleSpec, l);
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
Oid roleid;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
roleid = get_rolespec_oid(rolespec, false);
|
2005-06-28 07:09:14 +02:00
|
|
|
result = lappend_oid(result, roleid);
|
1999-12-16 18:24:19 +01:00
|
|
|
}
|
2005-06-28 07:09:14 +02:00
|
|
|
return result;
|
1999-12-16 18:24:19 +01:00
|
|
|
}
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* AddRoleMems -- Add given members to the specified role
|
|
|
|
*
|
2023-01-05 20:33:35 +01:00
|
|
|
* currentUserId: OID of role performing the operation
|
2005-06-28 07:09:14 +02:00
|
|
|
* rolename: name of role to add to (used only for error messages)
|
|
|
|
* roleid: OID of role to add to
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
* memberSpecs: list of RoleSpec of roles to add (used only for error messages)
|
2005-06-28 07:09:14 +02:00
|
|
|
* memberIds: OIDs of roles to add
|
2023-01-05 20:33:35 +01:00
|
|
|
* grantorId: OID that should be recorded as having granted the membership
|
|
|
|
* (InvalidOid if not set explicitly)
|
2022-08-25 16:06:02 +02:00
|
|
|
* popt: information about grant options
|
2000-01-14 23:11:38 +01:00
|
|
|
*/
|
2005-06-28 07:09:14 +02:00
|
|
|
static void
|
2023-01-05 20:33:35 +01:00
|
|
|
AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
List *memberSpecs, List *memberIds,
|
2022-08-25 16:06:02 +02:00
|
|
|
Oid grantorId, GrantRoleOptions *popt)
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
Relation pg_authmem_rel;
|
|
|
|
TupleDesc pg_authmem_dsc;
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
ListCell *specitem;
|
2005-06-28 07:09:14 +02:00
|
|
|
ListCell *iditem;
|
1999-12-16 18:24:19 +01:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
Assert(list_length(memberSpecs) == list_length(memberIds));
|
2000-01-14 23:11:38 +01:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
/* Validate grantor (and resolve implicit grantor if not specified). */
|
|
|
|
grantorId = check_role_grantor(currentUserId, roleid, grantorId, true);
|
2005-06-29 22:34:15 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
|
2005-06-28 07:09:14 +02:00
|
|
|
pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
|
2000-11-16 23:30:52 +01:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
/*
|
|
|
|
* Only allow changes to this role by one backend at a time, so that we
|
|
|
|
* can check integrity constraints like the lack of circular ADMIN OPTION
|
|
|
|
* grants without fear of race conditions.
|
|
|
|
*/
|
|
|
|
LockSharedObject(AuthIdRelationId, roleid, 0,
|
|
|
|
ShareUpdateExclusiveLock);
|
|
|
|
|
|
|
|
/* Preliminary sanity checks. */
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
forboth(specitem, memberSpecs, iditem, memberIds)
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
2020-04-25 06:09:30 +02:00
|
|
|
RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
|
2005-06-28 07:09:14 +02:00
|
|
|
Oid memberid = lfirst_oid(iditem);
|
|
|
|
|
2021-03-26 18:42:17 +01:00
|
|
|
/*
|
|
|
|
* pg_database_owner is never a role member. Lifting this restriction
|
|
|
|
* would require a policy decision about membership loops. One could
|
|
|
|
* prevent loops, which would include making "ALTER DATABASE x OWNER
|
|
|
|
* TO proposed_datdba" fail if is_member_of_role(pg_database_owner,
|
|
|
|
* proposed_datdba). Hence, gaining a membership could reduce what a
|
|
|
|
* role could do. Alternately, one could allow these memberships to
|
|
|
|
* complete loops. A role could then have actual WITH ADMIN OPTION on
|
|
|
|
* itself, prompting a decision about is_admin_of_role() treatment of
|
|
|
|
* the case.
|
|
|
|
*
|
|
|
|
* Lifting this restriction also has policy implications for ownership
|
|
|
|
* of shared objects (databases and tablespaces). We allow such
|
|
|
|
* ownership, but we might find cause to ban it in the future.
|
|
|
|
* Designing such a ban would more troublesome if the design had to
|
|
|
|
* address pg_database_owner being a member of role FOO that owns a
|
|
|
|
* shared object. (The effect of such ownership is that any owner of
|
|
|
|
* another database can act as the owner of affected shared objects.)
|
|
|
|
*/
|
2021-04-10 21:01:41 +02:00
|
|
|
if (memberid == ROLE_PG_DATABASE_OWNER)
|
2021-03-26 18:42:17 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
errmsg("role \"%s\" cannot be a member of any role",
|
|
|
|
get_rolespec_name(memberRole)));
|
|
|
|
|
2005-06-29 22:34:15 +02:00
|
|
|
/*
|
|
|
|
* Refuse creation of membership loops, including the trivial case
|
|
|
|
* where a role is made a member of itself. We do this by checking to
|
|
|
|
* see if the target role is already a member of the proposed member
|
2005-11-04 18:25:15 +01:00
|
|
|
* role. We have to ignore possible superuserness, however, else we
|
|
|
|
* could never grant membership in a superuser-privileged role.
|
2005-06-29 22:34:15 +02:00
|
|
|
*/
|
2005-11-04 18:25:15 +01:00
|
|
|
if (is_member_of_role_nosuper(roleid, memberid))
|
2005-06-29 22:34:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
2020-01-30 17:32:04 +01:00
|
|
|
errmsg("role \"%s\" is a member of role \"%s\"",
|
|
|
|
rolename, get_rolespec_name(memberRole))));
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disallow attempts to grant ADMIN OPTION back to a user who granted it
|
|
|
|
* to you, similar to what check_circularity does for ACLs. We want the
|
|
|
|
* chains of grants to remain acyclic, so that it's always possible to use
|
|
|
|
* REVOKE .. CASCADE to clean up all grants that depend on the one being
|
|
|
|
* revoked.
|
|
|
|
*
|
|
|
|
* NB: This check might look redundant with the check for membership loops
|
|
|
|
* above, but it isn't. That's checking for role-member loop (e.g. A is a
|
|
|
|
* member of B and B is a member of A) while this is checking for a
|
|
|
|
* member-grantor loop (e.g. A gave ADMIN OPTION on X to B and now B, who
|
|
|
|
* has no other source of ADMIN OPTION on X, tries to give ADMIN OPTION on
|
|
|
|
* X back to A).
|
|
|
|
*/
|
2022-08-25 16:06:02 +02:00
|
|
|
if (popt->admin && grantorId != BOOTSTRAP_SUPERUSERID)
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
{
|
|
|
|
CatCList *memlist;
|
|
|
|
RevokeRoleGrantAction *actions;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Get the list of members for this role. */
|
|
|
|
memlist = SearchSysCacheList1(AUTHMEMROLEMEM,
|
|
|
|
ObjectIdGetDatum(roleid));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out what would happen if we removed all existing grants to
|
|
|
|
* every role to which we've been asked to make a new grant.
|
|
|
|
*/
|
|
|
|
actions = initialize_revoke_actions(memlist);
|
|
|
|
foreach(iditem, memberIds)
|
|
|
|
{
|
|
|
|
Oid memberid = lfirst_oid(iditem);
|
|
|
|
|
|
|
|
if (memberid == BOOTSTRAP_SUPERUSERID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("%s option cannot be granted back to your own grantor",
|
|
|
|
"ADMIN")));
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
plan_member_revoke(memlist, actions, memberid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the result would be that the grantor role would no longer have
|
|
|
|
* the ability to perform the grant, then the proposed grant would
|
|
|
|
* create a circularity.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < memlist->n_members; ++i)
|
|
|
|
{
|
|
|
|
HeapTuple authmem_tuple;
|
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
|
|
|
|
authmem_tuple = &memlist->members[i]->tuple;
|
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
|
|
|
|
|
|
|
|
if (actions[i] == RRG_NOOP &&
|
|
|
|
authmem_form->member == grantorId &&
|
|
|
|
authmem_form->admin_option)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i >= memlist->n_members)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("%s option cannot be granted back to your own grantor",
|
|
|
|
"ADMIN")));
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
|
|
|
|
ReleaseSysCacheList(memlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now perform the catalog updates. */
|
|
|
|
forboth(specitem, memberSpecs, iditem, memberIds)
|
|
|
|
{
|
|
|
|
RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
|
|
|
|
Oid memberid = lfirst_oid(iditem);
|
|
|
|
HeapTuple authmem_tuple;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Datum new_record[Natts_pg_auth_members] = {0};
|
|
|
|
bool new_record_nulls[Natts_pg_auth_members] = {0};
|
|
|
|
bool new_record_repl[Natts_pg_auth_members] = {0};
|
2005-06-29 22:34:15 +02:00
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
/* Common initialization for possible insert or update */
|
|
|
|
new_record[Anum_pg_auth_members_roleid - 1] =
|
|
|
|
ObjectIdGetDatum(roleid);
|
|
|
|
new_record[Anum_pg_auth_members_member - 1] =
|
|
|
|
ObjectIdGetDatum(memberid);
|
|
|
|
new_record[Anum_pg_auth_members_grantor - 1] =
|
|
|
|
ObjectIdGetDatum(grantorId);
|
|
|
|
|
|
|
|
/* Find any existing tuple */
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
authmem_tuple = SearchSysCache3(AUTHMEMROLEMEM,
|
2010-02-14 19:42:19 +01:00
|
|
|
ObjectIdGetDatum(roleid),
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
ObjectIdGetDatum(memberid),
|
|
|
|
ObjectIdGetDatum(grantorId));
|
2022-08-25 16:06:02 +02:00
|
|
|
|
|
|
|
/*
|
2023-05-19 23:24:48 +02:00
|
|
|
* If we found a tuple, update it with new option values, unless there
|
|
|
|
* are no changes, in which case issue a WARNING.
|
2022-08-25 16:06:02 +02:00
|
|
|
*
|
|
|
|
* If we didn't find a tuple, just insert one.
|
|
|
|
*/
|
|
|
|
if (HeapTupleIsValid(authmem_tuple))
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
{
|
2022-08-25 16:06:02 +02:00
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
bool at_least_one_change = false;
|
|
|
|
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
|
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
if ((popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0
|
|
|
|
&& authmem_form->admin_option != popt->admin)
|
|
|
|
{
|
|
|
|
new_record[Anum_pg_auth_members_admin_option - 1] =
|
|
|
|
BoolGetDatum(popt->admin);
|
|
|
|
new_record_repl[Anum_pg_auth_members_admin_option - 1] =
|
|
|
|
true;
|
|
|
|
at_least_one_change = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0
|
|
|
|
&& authmem_form->inherit_option != popt->inherit)
|
|
|
|
{
|
|
|
|
new_record[Anum_pg_auth_members_inherit_option - 1] =
|
|
|
|
BoolGetDatum(popt->inherit);
|
|
|
|
new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
|
|
|
|
true;
|
|
|
|
at_least_one_change = true;
|
|
|
|
}
|
|
|
|
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0
|
|
|
|
&& authmem_form->set_option != popt->set)
|
|
|
|
{
|
|
|
|
new_record[Anum_pg_auth_members_set_option - 1] =
|
|
|
|
BoolGetDatum(popt->set);
|
|
|
|
new_record_repl[Anum_pg_auth_members_set_option - 1] =
|
|
|
|
true;
|
|
|
|
at_least_one_change = true;
|
|
|
|
}
|
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
if (!at_least_one_change)
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
{
|
|
|
|
ereport(NOTICE,
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
(errmsg("role \"%s\" has already been granted membership in role \"%s\" by role \"%s\"",
|
|
|
|
get_rolespec_name(memberRole), rolename,
|
|
|
|
GetUserNameFromId(grantorId, false))));
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
ReleaseSysCache(authmem_tuple);
|
|
|
|
continue;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
|
2005-06-28 07:09:14 +02:00
|
|
|
new_record,
|
|
|
|
new_record_nulls, new_record_repl);
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
ReleaseSysCache(authmem_tuple);
|
2000-01-14 23:11:38 +01:00
|
|
|
}
|
1999-12-16 18:24:19 +01:00
|
|
|
else
|
|
|
|
{
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
Oid objectId;
|
|
|
|
Oid *newmembers = palloc(sizeof(Oid));
|
|
|
|
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
/*
|
|
|
|
* The values for these options can be taken directly from 'popt'.
|
|
|
|
* Either they were specified, or the defaults as set by
|
|
|
|
* InitGrantRoleOptions are correct.
|
|
|
|
*/
|
2022-08-25 16:06:02 +02:00
|
|
|
new_record[Anum_pg_auth_members_admin_option - 1] =
|
|
|
|
BoolGetDatum(popt->admin);
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
new_record[Anum_pg_auth_members_set_option - 1] =
|
|
|
|
BoolGetDatum(popt->set);
|
2022-08-25 16:06:02 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the user specified a value for the inherit option, use
|
|
|
|
* whatever was specified. Otherwise, set the default value based
|
|
|
|
* on the role-level property.
|
|
|
|
*/
|
|
|
|
if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
|
|
|
|
new_record[Anum_pg_auth_members_inherit_option - 1] =
|
|
|
|
popt->inherit;
|
|
|
|
else
|
|
|
|
{
|
2023-05-19 23:24:48 +02:00
|
|
|
HeapTuple mrtup;
|
|
|
|
Form_pg_authid mrform;
|
2022-08-25 16:06:02 +02:00
|
|
|
|
|
|
|
mrtup = SearchSysCache1(AUTHOID, memberid);
|
|
|
|
if (!HeapTupleIsValid(mrtup))
|
|
|
|
elog(ERROR, "cache lookup failed for role %u", memberid);
|
|
|
|
mrform = (Form_pg_authid) GETSTRUCT(mrtup);
|
|
|
|
new_record[Anum_pg_auth_members_inherit_option - 1] =
|
|
|
|
mrform->rolinherit;
|
|
|
|
ReleaseSysCache(mrtup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get an OID for the new row and insert it */
|
2022-12-12 01:01:39 +01:00
|
|
|
objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId,
|
|
|
|
Anum_pg_auth_members_oid);
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
new_record[Anum_pg_auth_members_oid - 1] = objectId;
|
2008-11-02 02:45:28 +01:00
|
|
|
tuple = heap_form_tuple(pg_authmem_dsc,
|
2005-06-28 07:09:14 +02:00
|
|
|
new_record, new_record_nulls);
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleInsert(pg_authmem_rel, tuple);
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
|
|
|
|
/* updateAclDependencies wants to pfree array inputs */
|
|
|
|
newmembers[0] = grantorId;
|
|
|
|
updateAclDependencies(AuthMemRelationId, objectId,
|
|
|
|
0, InvalidOid,
|
|
|
|
0, NULL,
|
|
|
|
1, newmembers);
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
2005-06-29 22:34:15 +02:00
|
|
|
|
|
|
|
/* CCI after each change, in case there are duplicates in list */
|
|
|
|
CommandCounterIncrement();
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2002-04-04 06:25:54 +02:00
|
|
|
/*
|
2009-09-01 04:54:52 +02:00
|
|
|
* Close pg_authmem, but keep lock till commit.
|
2002-04-04 06:25:54 +02:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pg_authmem_rel, NoLock);
|
1999-12-16 18:24:19 +01:00
|
|
|
}
|
|
|
|
|
2002-04-27 23:24:34 +02:00
|
|
|
/*
|
2005-06-28 07:09:14 +02:00
|
|
|
* DelRoleMems -- Remove given members from the specified role
|
|
|
|
*
|
|
|
|
* rolename: name of role to del from (used only for error messages)
|
|
|
|
* roleid: OID of role to del from
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
* memberSpecs: list of RoleSpec of roles to del (used only for error messages)
|
2005-06-28 07:09:14 +02:00
|
|
|
* memberIds: OIDs of roles to del
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
* grantorId: who is revoking the membership
|
2022-08-25 16:06:02 +02:00
|
|
|
* popt: information about grant options
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
* behavior: RESTRICT or CASCADE behavior for recursive removal
|
2002-04-27 23:24:34 +02:00
|
|
|
*/
|
|
|
|
static void
|
2023-01-05 20:33:35 +01:00
|
|
|
DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
List *memberSpecs, List *memberIds,
|
2022-08-25 16:06:02 +02:00
|
|
|
Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior)
|
2002-04-27 23:24:34 +02:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
Relation pg_authmem_rel;
|
|
|
|
TupleDesc pg_authmem_dsc;
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
ListCell *specitem;
|
2005-06-28 07:09:14 +02:00
|
|
|
ListCell *iditem;
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
CatCList *memlist;
|
|
|
|
RevokeRoleGrantAction *actions;
|
|
|
|
int i;
|
2002-04-27 23:24:34 +02:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
Assert(list_length(memberSpecs) == list_length(memberIds));
|
2005-06-28 07:09:14 +02:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
/* Validate grantor (and resolve implicit grantor if not specified). */
|
|
|
|
grantorId = check_role_grantor(currentUserId, roleid, grantorId, false);
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
|
2005-06-28 07:09:14 +02:00
|
|
|
pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
|
1999-12-16 18:24:19 +01:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
/*
|
|
|
|
* Only allow changes to this role by one backend at a time, so that we
|
|
|
|
* can check for things like dependent privileges without fear of race
|
|
|
|
* conditions.
|
|
|
|
*/
|
|
|
|
LockSharedObject(AuthIdRelationId, roleid, 0,
|
|
|
|
ShareUpdateExclusiveLock);
|
|
|
|
|
|
|
|
memlist = SearchSysCacheList1(AUTHMEMROLEMEM, ObjectIdGetDatum(roleid));
|
|
|
|
actions = initialize_revoke_actions(memlist);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We may need to recurse to dependent privileges if DROP_CASCADE was
|
|
|
|
* specified, or refuse to perform the operation if dependent privileges
|
|
|
|
* exist and DROP_RESTRICT was specified. plan_single_revoke() will figure
|
|
|
|
* out what to do with each catalog tuple.
|
|
|
|
*/
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
forboth(specitem, memberSpecs, iditem, memberIds)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
RoleSpec *memberRole = lfirst(specitem);
|
2005-06-28 07:09:14 +02:00
|
|
|
Oid memberid = lfirst_oid(iditem);
|
1999-12-16 18:24:19 +01:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
if (!plan_single_revoke(memlist, actions, memberid, grantorId,
|
2022-08-25 16:06:02 +02:00
|
|
|
popt, behavior))
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
|
|
|
ereport(WARNING,
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
(errmsg("role \"%s\" has not been granted membership in role \"%s\" by role \"%s\"",
|
|
|
|
get_rolespec_name(memberRole), rolename,
|
|
|
|
GetUserNameFromId(grantorId, false))));
|
2005-06-28 07:09:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
}
|
2002-10-21 21:46:45 +02:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
/*
|
|
|
|
* We now know what to do with each catalog tuple: it should either be
|
|
|
|
* left alone, deleted, or just have the admin_option flag cleared.
|
|
|
|
* Perform the appropriate action in each case.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < memlist->n_members; ++i)
|
|
|
|
{
|
|
|
|
HeapTuple authmem_tuple;
|
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
|
|
|
|
if (actions[i] == RRG_NOOP)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
authmem_tuple = &memlist->members[i]->tuple;
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
|
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
if (actions[i] == RRG_DELETE_GRANT)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
Ensure that pg_auth_members.grantor is always valid.
Previously, "GRANT foo TO bar" or "GRANT foo TO bar GRANTED BY baz"
would record the OID of the grantor in pg_auth_members.grantor, but
that role could later be dropped without modifying or removing the
pg_auth_members record. That's not great, because we typically try
to avoid dangling references in catalog data.
Now, a role grant depends on the grantor, and the grantor can't be
dropped without removing the grant or changing the grantor. "DROP
OWNED BY" will remove the grant, just as it does for other kinds of
privileges. "REASSIGN OWNED BY" will not, again just like what we do
in other cases involving privileges.
pg_auth_members now has an OID column, because that is needed in order
for dependencies to work. It also now has an index on the grantor
column, because otherwise dropping a role would require a sequential
scan of the entire table to see whether the role's OID is in use as
a grantor. That probably wouldn't be too large a problem in practice,
but it seems better to have an index just in case.
A follow-on patch is planned with the goal of more thoroughly
rationalizing the behavior of role grants. This patch is just trying
to do enough to make sure that the data we store in the catalogs is at
some basic level valid.
Patch by me, reviewed by Stephen Frost
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-18 19:13:02 +02:00
|
|
|
/*
|
|
|
|
* Remove the entry altogether, after first removing its
|
|
|
|
* dependencies
|
|
|
|
*/
|
|
|
|
deleteSharedDependencyRecordsFor(AuthMemRelationId,
|
|
|
|
authmem_form->oid, 0);
|
2017-02-01 22:13:30 +01:00
|
|
|
CatalogTupleDelete(pg_authmem_rel, &authmem_tuple->t_self);
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-25 16:06:02 +02:00
|
|
|
/* Just turn off the specified option */
|
2005-06-28 07:09:14 +02:00
|
|
|
HeapTuple tuple;
|
2022-07-16 08:42:15 +02:00
|
|
|
Datum new_record[Natts_pg_auth_members] = {0};
|
|
|
|
bool new_record_nulls[Natts_pg_auth_members] = {0};
|
|
|
|
bool new_record_repl[Natts_pg_auth_members] = {0};
|
2005-06-28 07:09:14 +02:00
|
|
|
|
|
|
|
/* Build a tuple to update with */
|
2022-08-25 16:06:02 +02:00
|
|
|
if (actions[i] == RRG_REMOVE_ADMIN_OPTION)
|
|
|
|
{
|
|
|
|
new_record[Anum_pg_auth_members_admin_option - 1] =
|
|
|
|
BoolGetDatum(false);
|
|
|
|
new_record_repl[Anum_pg_auth_members_admin_option - 1] =
|
|
|
|
true;
|
|
|
|
}
|
|
|
|
else if (actions[i] == RRG_REMOVE_INHERIT_OPTION)
|
|
|
|
{
|
|
|
|
new_record[Anum_pg_auth_members_inherit_option - 1] =
|
|
|
|
BoolGetDatum(false);
|
|
|
|
new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
|
|
|
|
true;
|
|
|
|
}
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
else if (actions[i] == RRG_REMOVE_SET_OPTION)
|
|
|
|
{
|
|
|
|
new_record[Anum_pg_auth_members_set_option - 1] =
|
|
|
|
BoolGetDatum(false);
|
|
|
|
new_record_repl[Anum_pg_auth_members_set_option - 1] =
|
|
|
|
true;
|
|
|
|
}
|
2022-08-25 16:06:02 +02:00
|
|
|
else
|
|
|
|
elog(ERROR, "unknown role revoke action");
|
2005-06-28 07:09:14 +02:00
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
|
2005-06-28 07:09:14 +02:00
|
|
|
new_record,
|
|
|
|
new_record_nulls, new_record_repl);
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
|
2005-06-28 07:09:14 +02:00
|
|
|
}
|
|
|
|
}
|
2002-04-27 23:24:34 +02:00
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
ReleaseSysCacheList(memlist);
|
|
|
|
|
2002-10-21 21:46:45 +02:00
|
|
|
/*
|
2009-09-01 04:54:52 +02:00
|
|
|
* Close pg_authmem, but keep lock till commit.
|
2002-10-21 21:46:45 +02:00
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pg_authmem_rel, NoLock);
|
2003-06-27 16:45:32 +02:00
|
|
|
}
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
|
2023-01-05 20:30:40 +01:00
|
|
|
/*
|
|
|
|
* Check that currentUserId has permission to modify the membership list for
|
|
|
|
* roleid. Throw an error if not.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_role_membership_authorization(Oid currentUserId, Oid roleid,
|
|
|
|
bool is_grant)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The charter of pg_database_owner is to have exactly one, implicit,
|
|
|
|
* situation-dependent member. There's no technical need for this
|
|
|
|
* restriction. (One could lift it and take the further step of making
|
|
|
|
* object_ownercheck(DatabaseRelationId, ...) equivalent to
|
|
|
|
* has_privs_of_role(roleid, ROLE_PG_DATABASE_OWNER), in which case
|
|
|
|
* explicit, situation-independent members could act as the owner of any
|
|
|
|
* database.)
|
|
|
|
*/
|
|
|
|
if (is_grant && roleid == ROLE_PG_DATABASE_OWNER)
|
|
|
|
ereport(ERROR,
|
|
|
|
errmsg("role \"%s\" cannot have explicit members",
|
|
|
|
GetUserNameFromId(roleid, false)));
|
|
|
|
|
|
|
|
/* To mess with a superuser role, you gotta be superuser. */
|
|
|
|
if (superuser_arg(roleid))
|
|
|
|
{
|
|
|
|
if (!superuser_arg(currentUserId))
|
2023-03-17 10:14:16 +01:00
|
|
|
{
|
|
|
|
if (is_grant)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to grant role \"%s\"",
|
|
|
|
GetUserNameFromId(roleid, false)),
|
|
|
|
errdetail("Only roles with the %s attribute may grant roles with %s.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to revoke role \"%s\"",
|
|
|
|
GetUserNameFromId(roleid, false)),
|
|
|
|
errdetail("Only roles with the %s attribute may revoke roles with %s.",
|
|
|
|
"SUPERUSER", "SUPERUSER")));
|
|
|
|
}
|
2023-01-05 20:30:40 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
* Otherwise, must have admin option on the role to be changed.
|
2023-01-05 20:30:40 +01:00
|
|
|
*/
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
if (!is_admin_of_role(currentUserId, roleid))
|
2023-03-17 10:14:16 +01:00
|
|
|
{
|
|
|
|
if (is_grant)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to grant role \"%s\"",
|
|
|
|
GetUserNameFromId(roleid, false)),
|
|
|
|
errdetail("Only roles with the %s option on role \"%s\" may grant this role.",
|
|
|
|
"ADMIN", GetUserNameFromId(roleid, false))));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to revoke role \"%s\"",
|
|
|
|
GetUserNameFromId(roleid, false)),
|
|
|
|
errdetail("Only roles with the %s option on role \"%s\" may revoke this role.",
|
|
|
|
"ADMIN", GetUserNameFromId(roleid, false))));
|
|
|
|
}
|
2023-01-05 20:30:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
/*
|
|
|
|
* Sanity-check, or infer, the grantor for a GRANT or REVOKE statement
|
|
|
|
* targeting a role.
|
|
|
|
*
|
|
|
|
* The grantor must always be either a role with ADMIN OPTION on the role in
|
|
|
|
* which membership is being granted, or the bootstrap superuser. This is
|
|
|
|
* similar to the restriction enforced by select_best_grantor, except that
|
|
|
|
* roles don't have owners, so we regard the bootstrap superuser as the
|
|
|
|
* implicit owner.
|
|
|
|
*
|
|
|
|
* If the grantor was not explicitly specified by the user, grantorId should
|
|
|
|
* be passed as InvalidOid, and this function will infer the user to be
|
|
|
|
* recorded as the grantor. In many cases, this will be the current user, but
|
|
|
|
* things get more complicated when the current user doesn't possess ADMIN
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
* OPTION on the role but rather relies on having SUPERUSER privileges, or
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
* on inheriting the privileges of a role which does have ADMIN OPTION. See
|
|
|
|
* below for details.
|
|
|
|
*
|
|
|
|
* If the grantor was specified by the user, then it must be a user that
|
|
|
|
* can legally be recorded as the grantor, as per the rule stated above.
|
|
|
|
* This is an integrity constraint, not a permissions check, and thus even
|
|
|
|
* superusers are subject to this restriction. However, there is also a
|
|
|
|
* permissions check: to specify a role as the grantor, the current user
|
|
|
|
* must possess the privileges of that role. Superusers will always pass
|
|
|
|
* this check, but for non-superusers it may lead to an error.
|
|
|
|
*
|
|
|
|
* The return value is the OID to be regarded as the grantor when executing
|
|
|
|
* the operation.
|
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
|
|
|
|
{
|
|
|
|
/* If the grantor ID was not specified, pick one to use. */
|
|
|
|
if (!OidIsValid(grantorId))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Grants where the grantor is recorded as the bootstrap superuser do
|
|
|
|
* not depend on any other existing grants, so always default to this
|
|
|
|
* interpretation when possible.
|
|
|
|
*/
|
Restrict the privileges of CREATEROLE users.
Previously, CREATEROLE users were permitted to make nearly arbitrary
changes to roles that they didn't create, with certain exceptions,
particularly superuser roles. Instead, allow CREATEROLE users to make such
changes to roles for which they possess ADMIN OPTION, and to
grant membership only in roles for which they possess ADMIN OPTION.
When a CREATEROLE user who is not a superuser creates a role, grant
ADMIN OPTION on the newly-created role to the creator, so that they
can administer roles they create or for which they have been given
privileges.
With these changes, CREATEROLE users still have very significant
powers that unprivileged users do not receive: they can alter, rename,
drop, comment on, change the password for, and change security labels
on roles. However, they can now do these things only for roles for
which they possess appropriate privileges, rather than all
non-superuser roles; moreover, they cannot grant a role such as
pg_execute_server_program unless they themselves possess it.
Patch by me, reviewed by Mark Dilger.
Discussion: https://postgr.es/m/CA+TgmobN59ct+Emmz6ig1Nua2Q-_o=r6DSD98KfU53kctq_kQw@mail.gmail.com
2023-01-10 18:44:30 +01:00
|
|
|
if (superuser_arg(currentUserId))
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
return BOOTSTRAP_SUPERUSERID;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise, the grantor must either have ADMIN OPTION on the role or
|
|
|
|
* inherit the privileges of a role which does. In the former case,
|
|
|
|
* record the grantor as the current user; in the latter, pick one of
|
|
|
|
* the roles that is "most directly" inherited by the current role
|
|
|
|
* (i.e. fewest "hops").
|
|
|
|
*
|
|
|
|
* (We shouldn't fail to find a best grantor, because we've already
|
|
|
|
* established that the current user has permission to perform the
|
|
|
|
* operation.)
|
|
|
|
*/
|
|
|
|
grantorId = select_best_admin(currentUserId, roleid);
|
|
|
|
if (!OidIsValid(grantorId))
|
|
|
|
elog(ERROR, "no possible grantors");
|
|
|
|
return grantorId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If an explicit grantor is specified, it must be a role whose privileges
|
|
|
|
* the current user possesses.
|
|
|
|
*
|
|
|
|
* It should also be a role that has ADMIN OPTION on the target role, but
|
|
|
|
* we check this condition only in case of GRANT. For REVOKE, no matching
|
|
|
|
* grant should exist anyway, but if it somehow does, let the user get rid
|
|
|
|
* of it.
|
|
|
|
*/
|
|
|
|
if (is_grant)
|
|
|
|
{
|
|
|
|
if (!has_privs_of_role(currentUserId, grantorId))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to grant privileges as role \"%s\"",
|
2023-03-17 10:14:16 +01:00
|
|
|
GetUserNameFromId(grantorId, false)),
|
|
|
|
errdetail("Only roles with privileges of role \"%s\" may grant privileges as this role.",
|
|
|
|
GetUserNameFromId(grantorId, false))));
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
|
|
|
|
if (grantorId != BOOTSTRAP_SUPERUSERID &&
|
|
|
|
select_best_admin(grantorId, roleid) != grantorId)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2023-03-17 10:14:16 +01:00
|
|
|
errmsg("permission denied to grant privileges as role \"%s\"",
|
|
|
|
GetUserNameFromId(grantorId, false)),
|
|
|
|
errdetail("The grantor must have the %s option on role \"%s\".",
|
|
|
|
"ADMIN", GetUserNameFromId(roleid, false))));
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!has_privs_of_role(currentUserId, grantorId))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to revoke privileges granted by role \"%s\"",
|
2023-03-17 10:14:16 +01:00
|
|
|
GetUserNameFromId(grantorId, false)),
|
|
|
|
errdetail("Only roles with privileges of role \"%s\" may revoke privileges granted by this role.",
|
|
|
|
GetUserNameFromId(grantorId, false))));
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a grantor was specified explicitly, always attribute the grant to
|
|
|
|
* that role (unless we error out above).
|
|
|
|
*/
|
|
|
|
return grantorId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize an array of RevokeRoleGrantAction objects.
|
|
|
|
*
|
|
|
|
* 'memlist' should be a list of all grants for the target role.
|
|
|
|
*
|
|
|
|
* This constructs an array indicating that no actions are to be performed;
|
|
|
|
* that is, every element is initially RRG_NOOP.
|
|
|
|
*/
|
|
|
|
static RevokeRoleGrantAction *
|
|
|
|
initialize_revoke_actions(CatCList *memlist)
|
|
|
|
{
|
|
|
|
RevokeRoleGrantAction *result;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (memlist->n_members == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
result = palloc(sizeof(RevokeRoleGrantAction) * memlist->n_members);
|
|
|
|
for (i = 0; i < memlist->n_members; i++)
|
|
|
|
result[i] = RRG_NOOP;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out what we would need to do in order to revoke a grant, or just the
|
|
|
|
* admin option on a grant, given that there might be dependent privileges.
|
|
|
|
*
|
|
|
|
* 'memlist' should be a list of all grants for the target role.
|
|
|
|
*
|
|
|
|
* Whatever actions prove to be necessary will be signalled by updating
|
|
|
|
* 'actions'.
|
|
|
|
*
|
|
|
|
* If behavior is DROP_RESTRICT, an error will occur if there are dependent
|
|
|
|
* role membership grants; if DROP_CASCADE, those grants will be scheduled
|
|
|
|
* for deletion.
|
|
|
|
*
|
|
|
|
* The return value is true if the matching grant was found in the list,
|
|
|
|
* and false if not.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
|
2022-08-25 16:06:02 +02:00
|
|
|
Oid member, Oid grantor, GrantRoleOptions *popt,
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
DropBehavior behavior)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2022-08-25 16:06:02 +02:00
|
|
|
/*
|
|
|
|
* If popt.specified == 0, we're revoking the grant entirely; otherwise,
|
|
|
|
* we expect just one bit to be set, and we're revoking the corresponding
|
2023-05-19 23:24:48 +02:00
|
|
|
* option. As of this writing, there's no syntax that would allow for an
|
|
|
|
* attempt to revoke multiple options at once, and the logic below
|
2022-08-25 16:06:02 +02:00
|
|
|
* wouldn't work properly if such syntax were added, so assert that our
|
|
|
|
* caller isn't trying to do that.
|
|
|
|
*/
|
|
|
|
Assert(pg_popcount32(popt->specified) <= 1);
|
|
|
|
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
for (i = 0; i < memlist->n_members; ++i)
|
|
|
|
{
|
|
|
|
HeapTuple authmem_tuple;
|
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
|
|
|
|
authmem_tuple = &memlist->members[i]->tuple;
|
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
|
|
|
|
|
|
|
|
if (authmem_form->member == member &&
|
|
|
|
authmem_form->grantor == grantor)
|
|
|
|
{
|
2022-08-25 16:06:02 +02:00
|
|
|
if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Revoking the INHERIT option doesn't change anything for
|
|
|
|
* dependent privileges, so we don't need to recurse.
|
|
|
|
*/
|
|
|
|
actions[i] = RRG_REMOVE_INHERIT_OPTION;
|
|
|
|
}
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
else if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0)
|
|
|
|
{
|
|
|
|
/* Here too, no need to recurse. */
|
|
|
|
actions[i] = RRG_REMOVE_SET_OPTION;
|
|
|
|
}
|
2022-08-25 16:06:02 +02:00
|
|
|
else
|
|
|
|
{
|
2023-05-19 23:24:48 +02:00
|
|
|
bool revoke_admin_option_only;
|
2022-08-25 16:06:02 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Revoking the grant entirely, or ADMIN option on a grant,
|
|
|
|
* implicates dependent privileges, so we may need to recurse.
|
|
|
|
*/
|
|
|
|
revoke_admin_option_only =
|
|
|
|
(popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0;
|
|
|
|
plan_recursive_revoke(memlist, actions, i,
|
|
|
|
revoke_admin_option_only, behavior);
|
|
|
|
}
|
Make role grant system more consistent with other privileges.
Previously, membership of role A in role B could be recorded in the
catalog tables only once. This meant that a new grant of role A to
role B would overwrite the previous grant. For other object types, a
new grant of permission on an object - in this case role A - exists
along side the existing grant provided that the grantor is different.
Either grant can be revoked independently of the other, and
permissions remain so long as at least one grant remains. Make role
grants work similarly.
Previously, when granting membership in a role, the superuser could
specify any role whatsoever as the grantor, but for other object types,
the grantor of record must be either the owner of the object, or a
role that currently has privileges to perform a similar GRANT.
Implement the same scheme for role grants, treating the bootstrap
superuser as the role owner since roles do not have owners. This means
that attempting to revoke a grant, or admin option on a grant, can now
fail if there are dependent privileges, and that CASCADE can be used
to revoke these. It also means that you can't grant ADMIN OPTION on
a role back to a user who granted it directly or indirectly to you,
similar to how you can't give WITH GRANT OPTION on a privilege back
to a role which granted it directly or indirectly to you.
Previously, only the superuser could specify GRANTED BY with a user
other than the current user. Relax that rule to allow the grantor
to be any role whose privileges the current user posseses. This
doesn't improve compatibility with what we do for other object types,
where support for GRANTED BY is entirely vestigial, but it makes this
feature more usable and seems to make sense to change at the same time
we're changing related behaviors.
Along the way, fix "ALTER GROUP group_name ADD USER user_name" to
require the same privileges as "GRANT group_name TO user_name".
Previously, CREATEROLE privileges were sufficient for either, but
only the former form was permissible with ADMIN OPTION on the role.
Now, either CREATEROLE or ADMIN OPTION on the role suffices for
either spelling.
Patch by me, reviewed by Stephen Frost.
Discussion: http://postgr.es/m/CA+TgmoaFr-RZeQ+WoQ5nKPv97oT9+aDgK_a5+qWHSgbDsMp1Vg@mail.gmail.com
2022-08-22 17:35:17 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out what we would need to do in order to revoke all grants to
|
|
|
|
* a given member, given that there might be dependent privileges.
|
|
|
|
*
|
|
|
|
* 'memlist' should be a list of all grants for the target role.
|
|
|
|
*
|
|
|
|
* Whatever actions prove to be necessary will be signalled by updating
|
|
|
|
* 'actions'.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
plan_member_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
|
|
|
|
Oid member)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < memlist->n_members; ++i)
|
|
|
|
{
|
|
|
|
HeapTuple authmem_tuple;
|
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
|
|
|
|
authmem_tuple = &memlist->members[i]->tuple;
|
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
|
|
|
|
|
|
|
|
if (authmem_form->member == member)
|
|
|
|
plan_recursive_revoke(memlist, actions, i, false, DROP_CASCADE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Workhorse for figuring out recursive revocation of role grants.
|
|
|
|
*
|
|
|
|
* This is similar to what recursive_revoke() does for ACLs.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
plan_recursive_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
|
|
|
|
int index,
|
|
|
|
bool revoke_admin_option_only, DropBehavior behavior)
|
|
|
|
{
|
|
|
|
bool would_still_have_admin_option = false;
|
|
|
|
HeapTuple authmem_tuple;
|
|
|
|
Form_pg_auth_members authmem_form;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* If it's already been done, we can just return. */
|
|
|
|
if (actions[index] == RRG_DELETE_GRANT)
|
|
|
|
return;
|
|
|
|
if (actions[index] == RRG_REMOVE_ADMIN_OPTION &&
|
|
|
|
revoke_admin_option_only)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Locate tuple data. */
|
|
|
|
authmem_tuple = &memlist->members[index]->tuple;
|
|
|
|
authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the existing tuple does not have admin_option set, then we do not
|
|
|
|
* need to recurse. If we're just supposed to clear that bit we don't need
|
|
|
|
* to do anything at all; if we're supposed to remove the grant, we need
|
|
|
|
* to do something, but only to the tuple, and not any others.
|
|
|
|
*/
|
|
|
|
if (!revoke_admin_option_only)
|
|
|
|
{
|
|
|
|
actions[index] = RRG_DELETE_GRANT;
|
|
|
|
if (!authmem_form->admin_option)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!authmem_form->admin_option)
|
|
|
|
return;
|
|
|
|
actions[index] = RRG_REMOVE_ADMIN_OPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine whether the member would still have ADMIN OPTION. */
|
|
|
|
for (i = 0; i < memlist->n_members; ++i)
|
|
|
|
{
|
|
|
|
HeapTuple am_cascade_tuple;
|
|
|
|
Form_pg_auth_members am_cascade_form;
|
|
|
|
|
|
|
|
am_cascade_tuple = &memlist->members[i]->tuple;
|
|
|
|
am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
|
|
|
|
|
|
|
|
if (am_cascade_form->member == authmem_form->member &&
|
|
|
|
am_cascade_form->admin_option && actions[i] == RRG_NOOP)
|
|
|
|
{
|
|
|
|
would_still_have_admin_option = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the member would still have ADMIN OPTION, we need not recurse. */
|
|
|
|
if (would_still_have_admin_option)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Recurse to grants that are not yet slated for deletion which have this
|
|
|
|
* member as the grantor.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < memlist->n_members; ++i)
|
|
|
|
{
|
|
|
|
HeapTuple am_cascade_tuple;
|
|
|
|
Form_pg_auth_members am_cascade_form;
|
|
|
|
|
|
|
|
am_cascade_tuple = &memlist->members[i]->tuple;
|
|
|
|
am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
|
|
|
|
|
|
|
|
if (am_cascade_form->grantor == authmem_form->member &&
|
|
|
|
actions[i] != RRG_DELETE_GRANT)
|
|
|
|
{
|
|
|
|
if (behavior == DROP_RESTRICT)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
|
|
|
errmsg("dependent privileges exist"),
|
|
|
|
errhint("Use CASCADE to revoke them too.")));
|
|
|
|
|
|
|
|
plan_recursive_revoke(memlist, actions, i, false, behavior);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-25 16:06:02 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize a GrantRoleOptions object with default values.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
InitGrantRoleOptions(GrantRoleOptions *popt)
|
|
|
|
{
|
|
|
|
popt->specified = 0;
|
|
|
|
popt->admin = false;
|
|
|
|
popt->inherit = false;
|
Add a SET option to the GRANT command.
Similar to how the INHERIT option controls whether or not the
permissions of the granted role are automatically available to the
grantee, the new SET permission controls whether or not the grantee
may use the SET ROLE command to assume the privileges of the granted
role.
In addition, the new SET permission controls whether or not it
is possible to transfer ownership of objects to the target role
or to create new objects owned by the target role using commands
such as CREATE DATABASE .. OWNER. We could alternatively have made
this controlled by the INHERIT option, or allow it when either
option is given. An advantage of this approach is that if you
are granted a predefined role with INHERIT TRUE, SET FALSE, you
can't go and create objects owned by that role.
The underlying theory here is that the ability to create objects
as a target role is not a privilege per se, and thus does not
depend on whether you inherit the target role's privileges. However,
it's surely something you could do anyway if you could SET ROLE
to the target role, and thus making it contingent on whether you
have that ability is reasonable.
Design review by Nathan Bossat, Wolfgang Walther, Jeff Davis,
Peter Eisentraut, and Stephen Frost.
Discussion: http://postgr.es/m/CA+Tgmob+zDSRS6JXYrgq0NWdzCXuTNzT5eK54Dn2hhgt17nm8A@mail.gmail.com
2022-11-18 18:32:50 +01:00
|
|
|
popt->set = true;
|
2022-08-25 16:06:02 +02:00
|
|
|
}
|
2023-01-10 18:44:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* GUC check_hook for createrole_self_grant
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
check_createrole_self_grant(char **newval, void **extra, GucSource source)
|
|
|
|
{
|
|
|
|
char *rawstring;
|
|
|
|
List *elemlist;
|
|
|
|
ListCell *l;
|
|
|
|
unsigned options = 0;
|
|
|
|
unsigned *result;
|
|
|
|
|
|
|
|
/* Need a modifiable copy of string */
|
|
|
|
rawstring = pstrdup(*newval);
|
|
|
|
|
|
|
|
if (!SplitIdentifierString(rawstring, ',', &elemlist))
|
|
|
|
{
|
|
|
|
/* syntax error in list */
|
|
|
|
GUC_check_errdetail("List syntax is invalid.");
|
|
|
|
pfree(rawstring);
|
|
|
|
list_free(elemlist);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(l, elemlist)
|
|
|
|
{
|
|
|
|
char *tok = (char *) lfirst(l);
|
|
|
|
|
|
|
|
if (pg_strcasecmp(tok, "SET") == 0)
|
|
|
|
options |= GRANT_ROLE_SPECIFIED_SET;
|
|
|
|
else if (pg_strcasecmp(tok, "INHERIT") == 0)
|
|
|
|
options |= GRANT_ROLE_SPECIFIED_INHERIT;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
|
|
|
|
pfree(rawstring);
|
|
|
|
list_free(elemlist);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(rawstring);
|
|
|
|
list_free(elemlist);
|
|
|
|
|
|
|
|
result = (unsigned *) guc_malloc(LOG, sizeof(unsigned));
|
|
|
|
*result = options;
|
|
|
|
*extra = result;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GUC assign_hook for createrole_self_grant
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
assign_createrole_self_grant(const char *newval, void *extra)
|
|
|
|
{
|
2023-05-19 23:24:48 +02:00
|
|
|
unsigned options = *(unsigned *) extra;
|
2023-01-10 18:44:49 +01:00
|
|
|
|
|
|
|
createrole_self_grant_enabled = (options != 0);
|
|
|
|
createrole_self_grant_options.specified = GRANT_ROLE_SPECIFIED_ADMIN
|
|
|
|
| GRANT_ROLE_SPECIFIED_INHERIT
|
|
|
|
| GRANT_ROLE_SPECIFIED_SET;
|
|
|
|
createrole_self_grant_options.admin = false;
|
|
|
|
createrole_self_grant_options.inherit =
|
|
|
|
(options & GRANT_ROLE_SPECIFIED_INHERIT) != 0;
|
|
|
|
createrole_self_grant_options.set =
|
|
|
|
(options & GRANT_ROLE_SPECIFIED_SET) != 0;
|
|
|
|
}
|