diff options
Diffstat (limited to 'src/backend/utils/misc/superuser.c')
-rw-r--r-- | src/backend/utils/misc/superuser.c | 69 |
1 files changed, 59 insertions, 10 deletions
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index ee6cc397e34..520dc470cdc 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -2,7 +2,11 @@ * * 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_shadow.usesuper directly, so that the escape hatch built in for + * the single-user case works. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group @@ -10,26 +14,33 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.30 2004/12/31 22:02:45 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.31 2005/05/29 20:38:06 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "access/heapam.h" #include "catalog/pg_shadow.h" -#include "commands/dbcommands.h" +#include "utils/inval.h" #include "utils/syscache.h" #include "miscadmin.h" /* + * In common cases the same userid (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 userid. The cache can be flushed + * at need by watching for cache update events on pg_shadow. + */ +static AclId last_userid = 0; /* 0 == cache not valid */ +static bool last_userid_is_super = false; +static bool userid_callback_registered = false; + +static void UseridCallback(Datum arg, Oid relid); + + +/* * 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) @@ -38,16 +49,24 @@ superuser(void) } +/* + * The specified userid has Postgres superuser privileges + */ bool superuser_arg(AclId userid) { - bool result = false; + bool result; HeapTuple utup; + /* Quick out for cache hit */ + if (AclIdIsValid(last_userid) && last_userid == userid) + return last_userid_is_super; + /* Special escape path in case you deleted all your users. */ if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID) return true; + /* OK, look up the information in pg_shadow */ utup = SearchSysCache(SHADOWSYSID, Int32GetDatum(userid), 0, 0, 0); @@ -56,5 +75,35 @@ superuser_arg(AclId userid) result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; ReleaseSysCache(utup); } + else + { + /* Report "not superuser" for invalid userids */ + result = false; + } + + /* If first time through, set up callback for cache flushes */ + if (!userid_callback_registered) + { + CacheRegisterSyscacheCallback(SHADOWSYSID, + UseridCallback, + (Datum) 0); + userid_callback_registered = true; + } + + /* Cache the result for next time */ + last_userid = userid; + last_userid_is_super = result; + return result; } + +/* + * UseridCallback + * Syscache inval callback function + */ +static void +UseridCallback(Datum arg, Oid relid) +{ + /* Invalidate our local cache in case user's superuserness changed */ + last_userid = 0; +} |