Veil2
Postgres extension for VPD implementations
veil2.c File Reference

Provides callable veil2 functions. These are written in C for performance and to ensure that they cannot be easily subverted. More...

#include "postgres.h"
#include "funcapi.h"
#include "catalog/pg_type.h"
#include "access/xact.h"
#include "executor/spi.h"
#include "access/htup_details.h"
#include "utils/builtins.h"
#include "veil2.h"
Include dependency graph for veil2.c:

Go to the source code of this file.

Data Structures

struct  ContextRolePrivs
 
struct  SessionRolePrivs
 
struct  SessionContext
 

Macros

#define CONTEXT_ROLEPRIVS_INCREMENT   16
 
#define CONTEXT_ROLEPRIVS_SIZE(elems)
 

Functions

static void findContext (int *p_idx, int scope_type, int scope)
 
static bool checkContext (int *p_idx, int scope_type, int scope, int priv)
 
static void freeContextRolePrivs (ContextRolePrivs *cp)
 
static void clear_session_roleprivs ()
 
static SessionRolePrivsextendSessionRolePrivs (SessionRolePrivs *session_roleprivs)
 
static void add_scope_roleprivs (int scope_type, int scope, Bitmap *roles, Bitmap *privs)
 
static void update_scope_roleprivs (int scope_type, int scope, Bitmap *roles, Bitmap *privs)
 
static bool error_if_no_session ()
 
static bool fetch_2ints (HeapTuple tuple, TupleDesc tupdesc, void *p_result)
 
static void create_temp_tables ()
 
static void do_reset_session (bool clear_context)
 
Datum veil2_session_ready (FunctionCallInfo fcinfo)
 
Datum veil2_reset_session (FunctionCallInfo fcinfo)
 
Datum veil2_reset_session_privs (FunctionCallInfo fcinfo)
 
Datum veil2_session_context (FunctionCallInfo fcinfo)
 
Datum veil2_session_privileges (FunctionCallInfo fcinfo)
 
Datum veil2_add_session_privileges (FunctionCallInfo fcinfo)
 
Datum veil2_update_session_privileges (FunctionCallInfo fcinfo)
 
Datum veil2_true (FunctionCallInfo fcinfo)
 
static bool checkSessionReady ()
 
Datum veil2_i_have_global_priv (FunctionCallInfo fcinfo)
 
Datum veil2_i_have_personal_priv (FunctionCallInfo fcinfo)
 
Datum veil2_i_have_priv_in_scope (FunctionCallInfo fcinfo)
 
Datum veil2_i_have_priv_in_scope_or_global (FunctionCallInfo fcinfo)
 
Datum veil2_i_have_priv_in_superior_scope (FunctionCallInfo fcinfo)
 
Datum veil2_i_have_priv_in_scope_or_superior (FunctionCallInfo fcinfo)
 
Datum veil2_i_have_priv_in_scope_or_superior_or_global (FunctionCallInfo fcinfo)
 
Datum veil2_result_counts (FunctionCallInfo fcinfo)
 
static text * textfromstr (char *in)
 
Datum veil2_docpath (FunctionCallInfo fcinfo)
 
Datum veil2_datapath (FunctionCallInfo fcinfo)
 
Datum veil2_version (FunctionCallInfo fcinfo)
 

Variables

static bool session_ready = ((bool) 0)
 
static int result_counts [] = {0, 0}
 
static SessionRolePrivssession_roleprivs = ((void *) 0)
 
static bool session_roleprivs_loaded = ((bool) 0)
 
static SessionContext session_context
 

Detailed Description

Provides callable veil2 functions. These are written in C for performance and to ensure that they cannot be easily subverted.

Author: Marc Munro
Copyright (c) 2020,2021 Marc Munro
License: GPL V3

Definition in file veil2.c.

Macro Definition Documentation

◆ CONTEXT_ROLEPRIVS_INCREMENT

#define CONTEXT_ROLEPRIVS_INCREMENT   16

How many ContextPrivs entries a SessionPrivs structure will be created with or extended by.

Definition at line 270 of file veil2.c.

◆ CONTEXT_ROLEPRIVS_SIZE

#define CONTEXT_ROLEPRIVS_SIZE (   elems)
Value:
( \
sizeof(SessionRolePrivs) + \
(sizeof(ContextRolePrivs) * \
#define CONTEXT_ROLEPRIVS_INCREMENT
Definition: veil2.c:270

Provide the size that we want our SessionRolePrivs structure to be.

Parameters
elemsthe number of ContextRolePrivs entries already in place. This will be increased by CONTEXT_ROLEPRIVS_INCREMENT.

Definition at line 277 of file veil2.c.

Function Documentation

◆ add_scope_roleprivs()

static void add_scope_roleprivs ( int  scope_type,
int  scope,
Bitmap *  roles,
Bitmap *  privs 
)
static

Add a ContextPrivs entry to session_roleprivs, from the parameters.

Parameters
scope_typeThe scope_type for the new entry
scopeThe scope scope for the new entry
rolesThe roles Bitmap for the new entry
privsThe privileges Bitmap for the new entry

Definition at line 329 of file veil2.c.

Here is the call graph for this function:

◆ checkContext()

static bool checkContext ( int *  p_idx,
int  scope_type,
int  scope,
int  priv 
)
static

Wrapper for findContext() that finds the context and checks for a privilege in a single operation.

Parameters
p_idxPointer to a cached index value for the entry in the session_roleprivs->active_contexts that the search should start from. This allows the caller to cache the last returned index in the hope that they will be looking for the same entry next time. If no cached value exists, the caller should provide -1. The index of the found ContextPrivs entry will be returned through this, or -1 if no context can be found.
scope_typeThe scope_type_id of the ContextPrivs entry we are looking for.
scopeThe scope_id of the ContextPrivs entry we are looking for.
privThe privilege to test for.
Returns
false if no context can be found, otherwise true if the user has priv in the supplied scope.

Definition at line 219 of file veil2.c.

Here is the call graph for this function:

◆ checkSessionReady()

static bool checkSessionReady ( )
static

Check whether a session has been properly initialized. If not, and we are supposed to fail in such a situation, fail with an appropriate error message. Otherwise return true if the session is ready to go.

Returns
boolean True if our session has been properly initialized.

Definition at line 810 of file veil2.c.

Here is the call graph for this function:

◆ clear_session_roleprivs()

static void clear_session_roleprivs ( )
static

Clear all ContextRolePrivs entries in session_roleprivs.

Definition at line 250 of file veil2.c.

Here is the call graph for this function:

◆ create_temp_tables()

static void create_temp_tables ( )
static

Create a temporary table used for handling privileges in become_user. Originally, more temp tables were used but these have been replaced by in memory structures for performance and security.

Definition at line 445 of file veil2.c.

Here is the call graph for this function:

◆ do_reset_session()

static void do_reset_session ( bool  clear_context)
static

Does the database donkey-work for veil2_reset_session().

Parameters
clear_contextWhether veil2_session_context should be cleared as well as the privileges temp tables.

Definition at line 463 of file veil2.c.

Here is the call graph for this function:

◆ error_if_no_session()

static bool error_if_no_session ( )
static

Predicate to indicate whether to raise an error if a privilege test function has been called prior to a session being established. If not, the privilege testing function should return false. The determination of whether to error or return false is based on the value of the veil2.system_parameter 'error on uninitialized session' at the time that the database session is established.

Returns
boolean, whether or not to raise an error.

Definition at line 395 of file veil2.c.

Here is the call graph for this function:

◆ extendSessionRolePrivs()

static SessionRolePrivs* extendSessionRolePrivs ( SessionRolePrivs session_roleprivs)
static

Definition at line 290 of file veil2.c.

◆ fetch_2ints()

static bool fetch_2ints ( HeapTuple  tuple,
TupleDesc  tupdesc,
void *  p_result 
)
static

This is a Fetch_fn() for dealing with tuples containing 2 integers. Its job is to populate the p_result parameter with 2 integers from a Postgres SPI query.

Parameters
tupleThe ::HeapTuple returned from a Postgres SPI query. This will contain a tuple of 2 integers.
tupdescThe ::TupleDesc returned from the same Postgres SPI query
p_resultPointer to a tuple_2ints struct into which the 2 integers from the SPI query will be placed.
Returns
bool false, indicating to veil2_query() that no more rows are expected.

Definition at line 428 of file veil2.c.

◆ findContext()

static void findContext ( int *  p_idx,
int  scope_type,
int  scope 
)
static

Locate a particular ContextPriv entry in session_roleprivs.

Parameters
p_idxPointer to a cached index value for the entry in the session_roleprivs->active_contexts that the search should start from. This allows the caller to cache the last returned index in the hope that they will be looking for the same entry next time. If no cached value exists, the caller should provide -1. The index of the found ContextPrivs entry will be returned through this, or -1 if no context can be found.
scope_typeThe scope_type_id of the ContextPrivs entry we are looking for.
scopeThe scope_id of the ContextPrivs entry we are looking for.

Definition at line 151 of file veil2.c.

◆ freeContextRolePrivs()

static void freeContextRolePrivs ( ContextRolePrivs cp)
static

Free a ContextRolePrivs entry. This just means freeing the privileges Bitmap and zeroing the pointer for it.

Parameters
cpThe ContextRolePrivs entry to be cleared out.

Definition at line 237 of file veil2.c.

◆ textfromstr()

static text* textfromstr ( char *  in)
static

Create a dynamically allocated text value as a copy of a C string.

Parameters
inString to be copied
Returns
Dynamically allocated (by palloc()) copy of in.

Definition at line 1169 of file veil2.c.

◆ update_scope_roleprivs()

static void update_scope_roleprivs ( int  scope_type,
int  scope,
Bitmap *  roles,
Bitmap *  privs 
)
static

Update a ContextPrivs entry in session_roleprivs with new roles and privs. If there is no matching entry, we do nothing.

Parameters
scope_typeThe scope_type for the entry to be updated.
scopeThe scope scope for the entry to be updated.
rolesThe new roles Bitmap for the entry
privsThe new privileges Bitmap for the entry

Definition at line 365 of file veil2.c.

Here is the call graph for this function:

◆ veil2_add_session_privileges()

Datum veil2_add_session_privileges ( FunctionCallInfo  fcinfo)

veil2.add_session_privileges(scope_type_id, scope_id, roles, privileges)

Create a new in-memory session_privileges record. Note that this must be called with records ordered by scope_type_id, and scope_id. This is because we use a binary search to match the relevant scope when "querying" this structure internally.

Parameters
integerscope_type_id The type of scope
integerscope_id The id of the actual scope
Bitmaproles The roles assigned in the context for this scope
Bitmapprivs The privileges that apply in this scope
Returns
void

Definition at line 751 of file veil2.c.

Here is the call graph for this function:

◆ veil2_datapath()

Datum veil2_datapath ( FunctionCallInfo  fcinfo)

Provide the path to where veil2 sql scripts should be stored on the server.

Returns
Text value containing the path.

Definition at line 1197 of file veil2.c.

Here is the call graph for this function:

◆ veil2_docpath()

Datum veil2_docpath ( FunctionCallInfo  fcinfo)

Provide the path to where documentation should be stored on the server.

Returns
Text value containing the path.

Definition at line 1185 of file veil2.c.

Here is the call graph for this function:

◆ veil2_i_have_global_priv()

Datum veil2_i_have_global_priv ( FunctionCallInfo  fcinfo)

veil2.i_have_global_priv(priv) returns bool

Predicate to determine whether the current session user has a given privilege, priv, with global scope.

Parameters
privilege_idInteger giving privilege to test for
Returns
boolean true if the session has the given privilege

Definition at line 835 of file veil2.c.

Here is the call graph for this function:

◆ veil2_i_have_personal_priv()

Datum veil2_i_have_personal_priv ( FunctionCallInfo  fcinfo)

veil2.i_have_personal_priv(priv, accessor_id) returns bool

Predicate to determine whether the current session user has a given privilege, priv, in their personal scope (ie for data pertaining to themselves).

Parameters
privilege_idInteger giving privilege to test for
accessor_idInteger id for a party from the record being checked.
Returns
boolean true if the session has the given privilege in the personal scope of the given accessor_id

Definition at line 864 of file veil2.c.

Here is the call graph for this function:

◆ veil2_i_have_priv_in_scope()

Datum veil2_i_have_priv_in_scope ( FunctionCallInfo  fcinfo)

veil2.i_have_priv_in_scope(priv, scope_type_id, scope_id) returns bool

Predicate to determine whether the current session user has a given privilege, priv, in a specific scope (scope_type_id, scope_id).

Parameters
privilege_idInteger giving privilege to test for
scope_type_idInteger id of the scope type to be checked
scope_idInteger id of the scop to be checked
Returns
boolean true if the session has the given privilege for the given scope_type_id and scope_id

Definition at line 895 of file veil2.c.

Here is the call graph for this function:

◆ veil2_i_have_priv_in_scope_or_global()

Datum veil2_i_have_priv_in_scope_or_global ( FunctionCallInfo  fcinfo)

veil2.i_have_priv_in_scope_or_global(priv, scope_type_id, scope_id) returns bool

Predicate to determine whether the current session user has a given privilege, priv, in a specific scope (scope_type_id, scope_id), or in global scope.

Parameters
privilege_idInteger giving privilege to test for
scope_type_idInteger id of the scope type to be checked
scope_idInteger id of the scop to be checked
Returns
boolean true if the session has the given privilege for the given scope_type_id and scope_id

Definition at line 927 of file veil2.c.

Here is the call graph for this function:

◆ veil2_i_have_priv_in_scope_or_superior()

Datum veil2_i_have_priv_in_scope_or_superior ( FunctionCallInfo  fcinfo)

veil2.i_have_priv_in_scope_or_superior(priv, scope_type_id, scope_id) returns bool

Predicate to determine whether the current session user has a given privilege, priv, in the supplied scope or a superior one: scope_type_id, scope_id.

Parameters
privilege_idInteger giving privilege to test for
scope_type_idInteger id of the scope type to be checked
scope_idInteger id of the scop to be checked
Returns
boolean true if the session has the given privilege in the scope given by scope_type_id and scope_id or a supeior one.

Definition at line 1019 of file veil2.c.

Here is the call graph for this function:

◆ veil2_i_have_priv_in_scope_or_superior_or_global()

Datum veil2_i_have_priv_in_scope_or_superior_or_global ( FunctionCallInfo  fcinfo)

veil2.i_have_priv_in_scope_or_superior_or_global(priv, scope_type_id, scope_id) returns bool

Predicate to determine whether the current session user has a given privilege, priv, in global_scope, or the supplied scope, or a superior one: scope_type_id, scope_id.

Parameters
privilege_idInteger giving privilege to test for
scope_type_idInteger id of the scope type to be checked
scope_idInteger id of the scop to be checked
Returns
boolean true if the session has the given privilege in the scope given by scope_type_id and scope_id or a supeior one or global scope.

Definition at line 1085 of file veil2.c.

Here is the call graph for this function:

◆ veil2_i_have_priv_in_superior_scope()

Datum veil2_i_have_priv_in_superior_scope ( FunctionCallInfo  fcinfo)

veil2.i_have_priv_in_superior_scope(priv, scope_type_id, scope_id) returns bool

Predicate to determine whether the current session user has a given privilege, priv, in a superior scope to that supplied: scope_type_id, scope_id.

Parameters
privilege_idInteger giving privilege to test for
scope_type_idInteger id of the scope type to be checked
scope_idInteger id of the scop to be checked
Returns
boolean true if the session has the given privilege in a scope superior to that given by scope_type_id and scope_id

Definition at line 963 of file veil2.c.

Here is the call graph for this function:

◆ veil2_reset_session()

Datum veil2_reset_session ( FunctionCallInfo  fcinfo)

veil2.reset_session() returns void

Resets a postgres session prior to the recording of session privilege information. This ensures that the Veil2 temporary tables, on which our security depends, exist and have not been tamperered with. Unless this function succeeds, the privilege testing functions veil2_i_have_global_priv(), veil2_i_have_personal_priv(), veil2_i_have_priv_in_scope() and veil2_i_have_priv_in_superior_scope() will always return false.

Returns
void

Definition at line 559 of file veil2.c.

Here is the call graph for this function:

◆ veil2_reset_session_privs()

Datum veil2_reset_session_privs ( FunctionCallInfo  fcinfo)

veil2.reset_session_privs() returns void

Clears the temp table and cached privileges for a postgres session and reloads them.

Returns
void

Definition at line 579 of file veil2.c.

Here is the call graph for this function:

◆ veil2_result_counts()

Datum veil2_result_counts ( FunctionCallInfo  fcinfo)

Return the number of times one of the i_have_privilege_xxxx() functions has returned false and true.

Returns
Record: false_count, true_count

Definition at line 1140 of file veil2.c.

◆ veil2_session_context()

Datum veil2_session_context ( FunctionCallInfo  fcinfo)

veil2.session_context(<optional variables>)

Optionally set (if variables are provided), and return the session context.

Returns
record

Definition at line 598 of file veil2.c.

◆ veil2_session_privileges()

Datum veil2_session_privileges ( FunctionCallInfo  fcinfo)

veil2.session_privileges()

Return the current in-memory session_privileges as though they were a SQL table.

Returns
setof record

Definition at line 672 of file veil2.c.

◆ veil2_session_ready()

Datum veil2_session_ready ( FunctionCallInfo  fcinfo)

veil2_session_ready() returns bool Predicate to indicate whether the current session has been properly initialized by veil2_reset_session(). It tests the static variable session_ready.

Returns
bool true if this session has been set up.

Definition at line 539 of file veil2.c.

◆ veil2_true()

Datum veil2_true ( FunctionCallInfo  fcinfo)

veil2.true(params) returns bool

Always return true, regardless of parameters. This is used to determine the minimum possible overhead for a privilege testing predicate, for performance measurements.

Returns
boolean true

Definition at line 796 of file veil2.c.

◆ veil2_update_session_privileges()

Datum veil2_update_session_privileges ( FunctionCallInfo  fcinfo)

veil2.update_session_privileges(scope_type_id, scope_id, roles, privileges)

Update an in-memory session_privileges record, with new roles and prvs bitmaps.

Parameters
integerscope_type_id The type of scope
integerscope_id The id of the actual scope
Bitmaproles The roles assigned in the context for this scope
Bitmapprivs The privileges that apply in this scope
Returns
void

Definition at line 775 of file veil2.c.

Here is the call graph for this function:

◆ veil2_version()

Datum veil2_version ( FunctionCallInfo  fcinfo)

Provide the veil2 version as a string.

Returns
Text value containing the version.

Definition at line 1209 of file veil2.c.

Here is the call graph for this function:

Variable Documentation

◆ result_counts

int result_counts[] = {0, 0}
static

Used to record counts of false and true results from the i_have_priv_xxx() functions.

Definition at line 74 of file veil2.c.

◆ session_context

SessionContext session_context
static
Initial value:
= { ((bool) 0) , 0, 0, 0, 0,
0, 0, 0, 0}

Definition at line 131 of file veil2.c.

◆ session_ready

bool session_ready = ((bool) 0)
static

Used to record whether the current session's temporary tables have been properly initialised using veil2_reset_session(). If not the privilege testing functions veil2_i_have_global_priv(), veil2_i_have_personal_priv(), veil2_i_have_priv_in_scope() and veil2_i_have_priv_in_superior_scope() will always return false. If you need to implement your own pl/pgsql base privilege testing function, it should call veil2_session_reeady() to ensure that privileges have been correctly set up.

The primary reason for this variable to exist is to ensure that a user cannot trick the privileges functions by creating their own session_privileges table.

Definition at line 67 of file veil2.c.

◆ session_roleprivs

SessionRolePrivs* session_roleprivs = ((void *) 0)
static

The SessionPrivs object for this session.

Definition at line 124 of file veil2.c.

◆ session_roleprivs_loaded

bool session_roleprivs_loaded = ((bool) 0)
static

Whether we have loaded our session's ContextPrivs into session memory.

Definition at line 129 of file veil2.c.