X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Futils%2Fmisc%2Fsuperuser.c;h=fdaa99e1f81a8e4ba04ce2b8f32c844a619949bf;hb=ee33b95d9c2ecec170bc517783d7268a4bd0c793;hp=5848b444199aa63c6f20e03cd9201172a74f8fd7;hpb=44fbe20d620d4f2e39aaa9896de4683e55b0d317;p=postgresql diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index 5848b44419..fdaa99e1f8 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -2,36 +2,45 @@ * * superuser.c * The superuser() function. Determines if user has superuser privilege. - * Also, a function to check for the owner (datdba) of a database. * + * All code should use either of these two functions to find out + * whether a given user is a superuser, rather than examining + * pg_authid.rolsuper directly, so that the escape hatch built in for + * the single-user case works. * - * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.22 2002/05/20 23:51:43 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.38 2008/09/09 18:58:08 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "access/heapam.h" -#include "catalog/catname.h" -#include "catalog/pg_database.h" -#include "catalog/pg_shadow.h" +#include "catalog/pg_authid.h" +#include "utils/inval.h" #include "utils/syscache.h" #include "miscadmin.h" -#include "utils/fmgroids.h" + + +/* + * In common cases the same roleid (ie, the session or current ID) will + * be queried repeatedly. So we maintain a simple one-entry cache for + * the status of the last requested roleid. The cache can be flushed + * at need by watching for cache update events on pg_authid. + */ +static Oid last_roleid = InvalidOid; /* InvalidOid == cache not valid */ +static bool last_roleid_is_super = false; +static bool roleid_callback_registered = false; + +static void RoleidCallback(Datum arg, int cacheid, ItemPointer tuplePtr); /* * The Postgres user running this command has Postgres superuser privileges - * - * All code should use either of these two functions to find out - * whether a given user is a superuser, rather than evaluating - * pg_shadow.usesuper directly, so that the escape hatch built in for - * the single-user case works. */ bool superuser(void) @@ -40,54 +49,61 @@ superuser(void) } +/* + * The specified role has Postgres superuser privileges + */ bool -superuser_arg(Oid userid) +superuser_arg(Oid roleid) { - bool result = false; - HeapTuple utup; + bool result; + HeapTuple rtup; + + /* Quick out for cache hit */ + if (OidIsValid(last_roleid) && last_roleid == roleid) + return last_roleid_is_super; /* Special escape path in case you deleted all your users. */ - if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID) + if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID) return true; - utup = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(userid), + /* OK, look up the information in pg_authid */ + rtup = SearchSysCache(AUTHOID, + ObjectIdGetDatum(roleid), 0, 0, 0); - if (HeapTupleIsValid(utup)) + if (HeapTupleIsValid(rtup)) + { + result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper; + ReleaseSysCache(rtup); + } + else + { + /* Report "not superuser" for invalid roleids */ + result = false; + } + + /* If first time through, set up callback for cache flushes */ + if (!roleid_callback_registered) { - result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; - ReleaseSysCache(utup); + CacheRegisterSyscacheCallback(AUTHOID, + RoleidCallback, + (Datum) 0); + roleid_callback_registered = true; } + + /* Cache the result for next time */ + last_roleid = roleid; + last_roleid_is_super = result; + return result; } - /* - * The Postgres user running this command is the owner of the specified - * database. + * UseridCallback + * Syscache inval callback function */ -bool -is_dbadmin(Oid dbid) +static void +RoleidCallback(Datum arg, int cacheid, ItemPointer tuplePtr) { - Relation pg_database; - ScanKeyData entry[1]; - HeapScanDesc scan; - HeapTuple dbtuple; - int32 dba; - - /* There's no syscache for pg_database, so must look the hard way */ - pg_database = heap_openr(DatabaseRelationName, AccessShareLock); - ScanKeyEntryInitialize(&entry[0], 0x0, - ObjectIdAttributeNumber, F_OIDEQ, - ObjectIdGetDatum(dbid)); - scan = heap_beginscan(pg_database, SnapshotNow, 1, entry); - dbtuple = heap_getnext(scan, ForwardScanDirection); - if (!HeapTupleIsValid(dbtuple)) - elog(ERROR, "database %u does not exist", dbid); - dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba; - heap_endscan(scan); - heap_close(pg_database, AccessShareLock); - - /* XXX some confusion about whether userids are OID or int4 ... */ - return (GetUserId() == (Oid) dba); + /* Invalidate our local cache in case role's superuserness changed */ + last_roleid = InvalidOid; }