LCOV - code coverage report
Current view: top level - src/backend/utils/misc - rls.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 31 32 96.9 %
Date: 2017-09-29 15:12:54 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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
      53       19056 : check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
      54             : {
      55       19056 :     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       19056 :     if (relid < (Oid) FirstNormalObjectId)
      64        7431 :         return RLS_NONE;
      65             : 
      66             :     /* Fetch relation's relrowsecurity and relforcerowsecurity flags */
      67       11625 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
      68       11625 :     if (!HeapTupleIsValid(tuple))
      69           0 :         return RLS_NONE;
      70       11625 :     classform = (Form_pg_class) GETSTRUCT(tuple);
      71             : 
      72       11625 :     relrowsecurity = classform->relrowsecurity;
      73       11625 :     relforcerowsecurity = classform->relforcerowsecurity;
      74             : 
      75       11625 :     ReleaseSysCache(tuple);
      76             : 
      77             :     /* Nothing to do if the relation does not have RLS */
      78       11625 :     if (!relrowsecurity)
      79       11235 :         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         390 :     if (has_bypassrls_privilege(user_id))
      89          41 :         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         349 :     amowner = pg_class_ownercheck(relid, user_id);
     100         349 :     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          47 :         if (!relforcerowsecurity || InNoForceRLSOperation())
     118          31 :             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         318 :     if (!row_security && !noError)
     126          10 :         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         308 :     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
     143           2 : row_security_active(PG_FUNCTION_ARGS)
     144             : {
     145             :     /* By OID */
     146           2 :     Oid         tableoid = PG_GETARG_OID(0);
     147             :     int         rls_status;
     148             : 
     149           2 :     rls_status = check_enable_rls(tableoid, InvalidOid, true);
     150           2 :     PG_RETURN_BOOL(rls_status == RLS_ENABLED);
     151             : }
     152             : 
     153             : Datum
     154           2 : row_security_active_name(PG_FUNCTION_ARGS)
     155             : {
     156             :     /* By qualified name */
     157           2 :     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           2 :     tablerel = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
     164           2 :     tableoid = RangeVarGetRelid(tablerel, NoLock, false);
     165             : 
     166           2 :     rls_status = check_enable_rls(tableoid, InvalidOid, true);
     167           2 :     PG_RETURN_BOOL(rls_status == RLS_ENABLED);
     168             : }

Generated by: LCOV version 1.11