1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * superuser.c |
4 | * The superuser() function. Determines if user has superuser privilege. |
5 | * |
6 | * All code should use either of these two functions to find out |
7 | * whether a given user is a superuser, rather than examining |
8 | * pg_authid.rolsuper directly, so that the escape hatch built in for |
9 | * the single-user case works. |
10 | * |
11 | * |
12 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
13 | * Portions Copyright (c) 1994, Regents of the University of California |
14 | * |
15 | * |
16 | * IDENTIFICATION |
17 | * src/backend/utils/misc/superuser.c |
18 | * |
19 | *------------------------------------------------------------------------- |
20 | */ |
21 | #include "postgres.h" |
22 | |
23 | #include "access/htup_details.h" |
24 | #include "catalog/pg_authid.h" |
25 | #include "utils/inval.h" |
26 | #include "utils/syscache.h" |
27 | #include "miscadmin.h" |
28 | |
29 | |
30 | /* |
31 | * In common cases the same roleid (ie, the session or current ID) will |
32 | * be queried repeatedly. So we maintain a simple one-entry cache for |
33 | * the status of the last requested roleid. The cache can be flushed |
34 | * at need by watching for cache update events on pg_authid. |
35 | */ |
36 | static Oid last_roleid = InvalidOid; /* InvalidOid == cache not valid */ |
37 | static bool last_roleid_is_super = false; |
38 | static bool roleid_callback_registered = false; |
39 | |
40 | static void RoleidCallback(Datum arg, int cacheid, uint32 hashvalue); |
41 | |
42 | |
43 | /* |
44 | * The Postgres user running this command has Postgres superuser privileges |
45 | */ |
46 | bool |
47 | superuser(void) |
48 | { |
49 | return superuser_arg(GetUserId()); |
50 | } |
51 | |
52 | |
53 | /* |
54 | * The specified role has Postgres superuser privileges |
55 | */ |
56 | bool |
57 | superuser_arg(Oid roleid) |
58 | { |
59 | bool result; |
60 | HeapTuple rtup; |
61 | |
62 | /* Quick out for cache hit */ |
63 | if (OidIsValid(last_roleid) && last_roleid == roleid) |
64 | return last_roleid_is_super; |
65 | |
66 | /* Special escape path in case you deleted all your users. */ |
67 | if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID) |
68 | return true; |
69 | |
70 | /* OK, look up the information in pg_authid */ |
71 | rtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); |
72 | if (HeapTupleIsValid(rtup)) |
73 | { |
74 | result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper; |
75 | ReleaseSysCache(rtup); |
76 | } |
77 | else |
78 | { |
79 | /* Report "not superuser" for invalid roleids */ |
80 | result = false; |
81 | } |
82 | |
83 | /* If first time through, set up callback for cache flushes */ |
84 | if (!roleid_callback_registered) |
85 | { |
86 | CacheRegisterSyscacheCallback(AUTHOID, |
87 | RoleidCallback, |
88 | (Datum) 0); |
89 | roleid_callback_registered = true; |
90 | } |
91 | |
92 | /* Cache the result for next time */ |
93 | last_roleid = roleid; |
94 | last_roleid_is_super = result; |
95 | |
96 | return result; |
97 | } |
98 | |
99 | /* |
100 | * RoleidCallback |
101 | * Syscache inval callback function |
102 | */ |
103 | static void |
104 | RoleidCallback(Datum arg, int cacheid, uint32 hashvalue) |
105 | { |
106 | /* Invalidate our local cache in case role's superuserness changed */ |
107 | last_roleid = InvalidOid; |
108 | } |
109 | |