1 /*-------------------------------------------------------------------------
2 *
3 * rls.c
4 * RLS-related utility functions.
5 *
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/utils/misc/rls.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 #include "postgres.h"
16
17 #include "access/htup.h"
18 #include "access/htup_details.h"
19 #include "access/transam.h"
20 #include "catalog/namespace.h"
21 #include "catalog/pg_class.h"
22 #include "miscadmin.h"
23 #include "utils/acl.h"
24 #include "utils/builtins.h"
25 #include "utils/elog.h"
26 #include "utils/lsyscache.h"
27 #include "utils/rls.h"
28 #include "utils/syscache.h"
29 #include "utils/varlena.h"
30
31
32 /*
33 * check_enable_rls
34 *
35 * Determine, based on the relation, row_security setting, and current role,
36 * if RLS is applicable to this query. RLS_NONE_ENV indicates that, while
37 * RLS is not to be added for this query, a change in the environment may change
38 * that. RLS_NONE means that RLS is not on the relation at all and therefore
39 * we don't need to worry about it. RLS_ENABLED means RLS should be implemented
40 * for the table and the plan cache needs to be invalidated if the environment
41 * changes.
42 *
43 * Handle checking as another role via checkAsUser (for views, etc). Pass
44 * InvalidOid to check the current user.
45 *
46 * If noError is set to 'true' then we just return RLS_ENABLED instead of doing
47 * an ereport() if the user has attempted to bypass RLS and they are not
48 * allowed to. This allows users to check if RLS is enabled without having to
49 * deal with the actual error case (eg: error cases which are trying to decide
50 * if the user should get data from the relation back as part of the error).
51 */
52 int
check_enable_rls(Oid relid,Oid checkAsUser,bool noError)53 check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
54 {
55 Oid user_id = checkAsUser ? checkAsUser : GetUserId();
56 HeapTuple tuple;
57 Form_pg_class classform;
58 bool relrowsecurity;
59 bool relforcerowsecurity;
60 bool amowner;
61
62 /* Nothing to do for built-in relations */
63 if (relid < (Oid) FirstNormalObjectId)
64 return RLS_NONE;
65
66 /* Fetch relation's relrowsecurity and relforcerowsecurity flags */
67 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
68 if (!HeapTupleIsValid(tuple))
69 return RLS_NONE;
70 classform = (Form_pg_class) GETSTRUCT(tuple);
71
72 relrowsecurity = classform->relrowsecurity;
73 relforcerowsecurity = classform->relforcerowsecurity;
74
75 ReleaseSysCache(tuple);
76
77 /* Nothing to do if the relation does not have RLS */
78 if (!relrowsecurity)
79 return RLS_NONE;
80
81 /*
82 * BYPASSRLS users always bypass RLS. Note that superusers are always
83 * considered to have BYPASSRLS.
84 *
85 * Return RLS_NONE_ENV to indicate that this decision depends on the
86 * environment (in this case, the user_id).
87 */
88 if (has_bypassrls_privilege(user_id))
89 return RLS_NONE_ENV;
90
91 /*
92 * Table owners generally bypass RLS, except if the table has been set (by
93 * an owner) to FORCE ROW SECURITY, and this is not a referential
94 * integrity check.
95 *
96 * Return RLS_NONE_ENV to indicate that this decision depends on the
97 * environment (in this case, the user_id).
98 */
99 amowner = pg_class_ownercheck(relid, user_id);
100 if (amowner)
101 {
102 /*
103 * If FORCE ROW LEVEL SECURITY has been set on the relation then we
104 * should return RLS_ENABLED to indicate that RLS should be applied.
105 * If not, or if we are in an InNoForceRLSOperation context, we return
106 * RLS_NONE_ENV.
107 *
108 * InNoForceRLSOperation indicates that we should not apply RLS even
109 * if the table has FORCE RLS set - IF the current user is the owner.
110 * This is specifically to ensure that referential integrity checks
111 * are able to still run correctly.
112 *
113 * This is intentionally only done after we have checked that the user
114 * is the table owner, which should always be the case for referential
115 * integrity checks.
116 */
117 if (!relforcerowsecurity || InNoForceRLSOperation())
118 return RLS_NONE_ENV;
119 }
120
121 /*
122 * We should apply RLS. However, the user may turn off the row_security
123 * GUC to get a forced error instead.
124 */
125 if (!row_security && !noError)
126 ereport(ERROR,
127 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
128 errmsg("query would be affected by row-level security policy for table \"%s\"",
129 get_rel_name(relid)),
130 amowner ? errhint("To disable the policy for the table's owner, use ALTER TABLE NO FORCE ROW LEVEL SECURITY.") : 0));
131
132 /* RLS should be fully enabled for this relation. */
133 return RLS_ENABLED;
134 }
135
136 /*
137 * row_security_active
138 *
139 * check_enable_rls wrapped as a SQL callable function except
140 * RLS_NONE_ENV and RLS_NONE are the same for this purpose.
141 */
142 Datum
row_security_active(PG_FUNCTION_ARGS)143 row_security_active(PG_FUNCTION_ARGS)
144 {
145 /* By OID */
146 Oid tableoid = PG_GETARG_OID(0);
147 int rls_status;
148
149 rls_status = check_enable_rls(tableoid, InvalidOid, true);
150 PG_RETURN_BOOL(rls_status == RLS_ENABLED);
151 }
152
153 Datum
row_security_active_name(PG_FUNCTION_ARGS)154 row_security_active_name(PG_FUNCTION_ARGS)
155 {
156 /* By qualified name */
157 text *tablename = PG_GETARG_TEXT_PP(0);
158 RangeVar *tablerel;
159 Oid tableoid;
160 int rls_status;
161
162 /* Look up table name. Can't lock it - we might not have privileges. */
163 tablerel = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
164 tableoid = RangeVarGetRelid(tablerel, NoLock, false);
165
166 rls_status = check_enable_rls(tableoid, InvalidOid, true);
167 PG_RETURN_BOOL(rls_status == RLS_ENABLED);
168 }
169