diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-07-26 00:04:19 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-07-26 00:04:19 +0000 |
commit | f9fd1764615ed5d85fab703b0ffb0c323fe7dfd5 (patch) | |
tree | fce5ae4aa26bd0f1f085358f9bdcd3cb60db7058 /src/backend/utils/adt/acl.c | |
parent | e5d6b91220d69c87f44e1ce0095516946abc6d6c (diff) | |
download | postgresql-f9fd1764615ed5d85fab703b0ffb0c323fe7dfd5.tar.gz postgresql-f9fd1764615ed5d85fab703b0ffb0c323fe7dfd5.zip |
Add pg_has_role() family of privilege inquiry functions modeled after the
existing ones for object privileges. Update the information_schema for
roles --- pg_has_role() makes this a whole lot easier, removing the need
for most of the explicit joins with pg_user. The views should be a tad
faster now, too. Stephen Frost and Tom Lane.
Diffstat (limited to 'src/backend/utils/adt/acl.c')
-rw-r--r-- | src/backend/utils/adt/acl.c | 222 |
1 files changed, 221 insertions, 1 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 36d53ca9ffc..7517f2743f9 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.120 2005/07/21 04:41:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.121 2005/07/26 00:04:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -75,6 +75,8 @@ static Oid convert_schema_name(text *schemaname); static AclMode convert_schema_priv_string(text *priv_type_text); static Oid convert_tablespace_name(text *tablespacename); static AclMode convert_tablespace_priv_string(text *priv_type_text); +static AclMode convert_role_priv_string(text *priv_type_text); +static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode); static void RoleMembershipCacheCallback(Datum arg, Oid relid); @@ -2494,6 +2496,216 @@ convert_tablespace_priv_string(text *priv_type_text) } /* + * pg_has_role variants + * These are all named "pg_has_role" at the SQL level. + * They take various combinations of role name, role OID, + * user name, user OID, or implicit user = current_user. + * + * The result is a boolean value: true if user has the indicated + * privilege, false if not. + */ + +/* + * pg_has_role_name_name + * Check user privileges on a role given + * name username, name rolename, and text priv name. + */ +Datum +pg_has_role_name_name(PG_FUNCTION_ARGS) +{ + Name username = PG_GETARG_NAME(0); + Name rolename = PG_GETARG_NAME(1); + text *priv_type_text = PG_GETARG_TEXT_P(2); + Oid roleid; + Oid roleoid; + AclMode mode; + AclResult aclresult; + + roleid = get_roleid_checked(NameStr(*username)); + roleoid = get_roleid_checked(NameStr(*rolename)); + mode = convert_role_priv_string(priv_type_text); + + aclresult = pg_role_aclcheck(roleoid, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * pg_has_role_name + * Check user privileges on a role given + * name rolename and text priv name. + * current_user is assumed + */ +Datum +pg_has_role_name(PG_FUNCTION_ARGS) +{ + Name rolename = PG_GETARG_NAME(0); + text *priv_type_text = PG_GETARG_TEXT_P(1); + Oid roleid; + Oid roleoid; + AclMode mode; + AclResult aclresult; + + roleid = GetUserId(); + roleoid = get_roleid_checked(NameStr(*rolename)); + mode = convert_role_priv_string(priv_type_text); + + aclresult = pg_role_aclcheck(roleoid, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * pg_has_role_name_id + * Check user privileges on a role given + * name usename, role oid, and text priv name. + */ +Datum +pg_has_role_name_id(PG_FUNCTION_ARGS) +{ + Name username = PG_GETARG_NAME(0); + Oid roleoid = PG_GETARG_OID(1); + text *priv_type_text = PG_GETARG_TEXT_P(2); + Oid roleid; + AclMode mode; + AclResult aclresult; + + roleid = get_roleid_checked(NameStr(*username)); + mode = convert_role_priv_string(priv_type_text); + + aclresult = pg_role_aclcheck(roleoid, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * pg_has_role_id + * Check user privileges on a role given + * role oid, and text priv name. + * current_user is assumed + */ +Datum +pg_has_role_id(PG_FUNCTION_ARGS) +{ + Oid roleoid = PG_GETARG_OID(0); + text *priv_type_text = PG_GETARG_TEXT_P(1); + Oid roleid; + AclMode mode; + AclResult aclresult; + + roleid = GetUserId(); + mode = convert_role_priv_string(priv_type_text); + + aclresult = pg_role_aclcheck(roleoid, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * pg_has_role_id_name + * Check user privileges on a role given + * roleid, name rolename, and text priv name. + */ +Datum +pg_has_role_id_name(PG_FUNCTION_ARGS) +{ + Oid roleid = PG_GETARG_OID(0); + Name rolename = PG_GETARG_NAME(1); + text *priv_type_text = PG_GETARG_TEXT_P(2); + Oid roleoid; + AclMode mode; + AclResult aclresult; + + roleoid = get_roleid_checked(NameStr(*rolename)); + mode = convert_role_priv_string(priv_type_text); + + aclresult = pg_role_aclcheck(roleoid, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * pg_has_role_id_id + * Check user privileges on a role given + * roleid, role oid, and text priv name. + */ +Datum +pg_has_role_id_id(PG_FUNCTION_ARGS) +{ + Oid roleid = PG_GETARG_OID(0); + Oid roleoid = PG_GETARG_OID(1); + text *priv_type_text = PG_GETARG_TEXT_P(2); + AclMode mode; + AclResult aclresult; + + mode = convert_role_priv_string(priv_type_text); + + aclresult = pg_role_aclcheck(roleoid, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * Support routines for pg_has_role family. + */ + +/* + * convert_role_priv_string + * Convert text string to AclMode value. + * + * There is only one interesting option, MEMBER, which we represent by + * ACL_USAGE since no formal ACL bit is defined for it. This convention + * is shared only with pg_role_aclcheck, below. + */ +static AclMode +convert_role_priv_string(text *priv_type_text) +{ + char *priv_type; + + priv_type = DatumGetCString(DirectFunctionCall1(textout, + PointerGetDatum(priv_type_text))); + + /* + * Return mode from priv_type string + */ + if (pg_strcasecmp(priv_type, "MEMBER") == 0) + return ACL_USAGE; + if (pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0) + return ACL_GRANT_OPTION_FOR(ACL_USAGE); + if (pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0) + return ACL_GRANT_OPTION_FOR(ACL_USAGE); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized privilege type: \"%s\"", priv_type))); + return ACL_NO_RIGHTS; /* keep compiler quiet */ +} + +/* + * pg_role_aclcheck + * Quick-and-dirty support for pg_has_role + */ +static AclResult +pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode) +{ + if (mode & ACL_GRANT_OPTION_FOR(ACL_USAGE)) + { + if (is_admin_of_role(roleid, role_oid)) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; + } + else + { + if (is_member_of_role(roleid, role_oid)) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; + } +} + + +/* * initialization function (called by InitPostgres) */ void @@ -2637,6 +2849,14 @@ is_admin_of_role(Oid member, Oid role) List *roles_list; ListCell *l; + /* Fast path for simple case */ + if (member == role) + return true; + + /* Superusers have every privilege, so are part of every role */ + if (superuser_arg(member)) + return true; + /* * Find all the roles that member is a member of, * including multi-level recursion. We build a list in the same way |