00001 /*------------------------------------------------------------------------- 00002 * 00003 * superuser.c 00004 * The superuser() function. Determines if user has superuser privilege. 00005 * 00006 * All code should use either of these two functions to find out 00007 * whether a given user is a superuser, rather than examining 00008 * pg_authid.rolsuper directly, so that the escape hatch built in for 00009 * the single-user case works. 00010 * 00011 * 00012 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group 00013 * Portions Copyright (c) 1994, Regents of the University of California 00014 * 00015 * 00016 * IDENTIFICATION 00017 * src/backend/utils/misc/superuser.c 00018 * 00019 *------------------------------------------------------------------------- 00020 */ 00021 #include "postgres.h" 00022 00023 #include "access/htup_details.h" 00024 #include "catalog/pg_authid.h" 00025 #include "utils/inval.h" 00026 #include "utils/syscache.h" 00027 #include "miscadmin.h" 00028 00029 00030 /* 00031 * In common cases the same roleid (ie, the session or current ID) will 00032 * be queried repeatedly. So we maintain a simple one-entry cache for 00033 * the status of the last requested roleid. The cache can be flushed 00034 * at need by watching for cache update events on pg_authid. 00035 */ 00036 static Oid last_roleid = InvalidOid; /* InvalidOid == cache not valid */ 00037 static bool last_roleid_is_super = false; 00038 static bool roleid_callback_registered = false; 00039 00040 static void RoleidCallback(Datum arg, int cacheid, uint32 hashvalue); 00041 00042 00043 /* 00044 * The Postgres user running this command has Postgres superuser privileges 00045 */ 00046 bool 00047 superuser(void) 00048 { 00049 return superuser_arg(GetUserId()); 00050 } 00051 00052 00053 /* 00054 * The specified role has Postgres superuser privileges 00055 */ 00056 bool 00057 superuser_arg(Oid roleid) 00058 { 00059 bool result; 00060 HeapTuple rtup; 00061 00062 /* Quick out for cache hit */ 00063 if (OidIsValid(last_roleid) && last_roleid == roleid) 00064 return last_roleid_is_super; 00065 00066 /* Special escape path in case you deleted all your users. */ 00067 if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID) 00068 return true; 00069 00070 /* OK, look up the information in pg_authid */ 00071 rtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); 00072 if (HeapTupleIsValid(rtup)) 00073 { 00074 result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper; 00075 ReleaseSysCache(rtup); 00076 } 00077 else 00078 { 00079 /* Report "not superuser" for invalid roleids */ 00080 result = false; 00081 } 00082 00083 /* If first time through, set up callback for cache flushes */ 00084 if (!roleid_callback_registered) 00085 { 00086 CacheRegisterSyscacheCallback(AUTHOID, 00087 RoleidCallback, 00088 (Datum) 0); 00089 roleid_callback_registered = true; 00090 } 00091 00092 /* Cache the result for next time */ 00093 last_roleid = roleid; 00094 last_roleid_is_super = result; 00095 00096 return result; 00097 } 00098 00099 /* 00100 * RoleidCallback 00101 * Syscache inval callback function 00102 */ 00103 static void 00104 RoleidCallback(Datum arg, int cacheid, uint32 hashvalue) 00105 { 00106 /* Invalidate our local cache in case role's superuserness changed */ 00107 last_roleid = InvalidOid; 00108 }