17 #include "catalog/pg_type.h" 18 #include "access/xact.h" 19 #include "executor/spi.h" 20 #include "utils/builtins.h" 26 /* These definitions are here rather than immediately preceding the 27 * function declarations themselves as this code seems to confuse 28 * Doxygen's call graph stuff. 132 else if ((
this < 0) || (
this >= upper)) {
133 /* Create a new start, in the middle of the contexts. */ 136 /* Bsearch until we find a match or realise there is none. */ 141 cmp = this_cp->
scope - scope;
148 /* We are looking for a lower value. */ 158 this = (upper + lower) >> 1;
189 return bitmapTestbit(
228 #define CONTEXT_PRIVS_INCREMENT 16 235 #define CONTEXT_PRIVS_SIZE(elems) ( \ 236 sizeof(SessionPrivs) + \ 237 (sizeof(ContextPrivs) * \ 238 (elems + CONTEXT_PRIVS_INCREMENT))) 241 * Create or extend our SessionPrivs structure. 243 * @result The newly allocated SessionPrivs struct. 256 i < session_privs->array_len; i++)
265 if (!session_privs) {
267 (errcode(ERRCODE_INTERNAL_ERROR),
268 errmsg(
"Unable to create session memory in " 269 "extendSessionPrivs()")));
285 MemoryContext old_context;
295 /* We copy the bitmap in TopMemoryContext so that it won't be 296 * cleaned-up as transactions come and go. */ 298 old_context = MemoryContextSwitchTo(TopMemoryContext);
300 MemoryContextSwitchTo(old_context);
325 scope_type = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 1, &isnull));
326 scope = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 2, &isnull));
327 privs = DatumGetBitmap(SPI_getbinval(tuple, tupdesc, 3, &isnull));
349 "SPI connect failed in do_load_session_privs() - veil2");
352 "select scope_type_id, scope_id, privs" 353 " from veil2_session_privileges" 360 "SPI finish failed in do_load_session_privs() - veil2");
389 static bool init_done =
false;
390 static bool error =
true;
395 "select parameter_value::boolean" 396 " from veil2.system_parameters" 397 " where parameter_name = 'error on uninitialized session'",
398 0, NULL, NULL, NULL, &error);
426 my_tup->
f1 = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 1, &isnull));
427 my_tup->
f2 = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 2, &isnull));
429 return false;
// No need to continue processing after this 441 "create temporary table veil2_session_privileges" 442 " of veil2.session_privileges_t",
447 "create temporary table veil2_ancestor_privileges" 448 " of veil2.session_privileges_t",
453 "create temporary table veil2_session_context" 454 " of veil2.session_context_t",
473 "delete from veil2_session_privileges",
479 "delete from veil2_session_context",
515 "select count(*)::integer," 516 " sum(case when c.relacl is null then 1 else 0 end)" 517 " from pg_catalog.pg_class c" 518 " where c.relname in ('veil2_session_privileges'," 519 " 'veil2_session_context'," 520 " 'veil2_ancestor_privileges')" 521 " and c.relkind = 'r'" 522 " and c.relpersistence = 't'" 523 " and pg_catalog.pg_table_is_visible(c.oid)",
528 if (processed == 0) {
529 /* Unexpected error in query. */ 531 (errcode(ERRCODE_INTERNAL_ERROR),
532 errmsg(
"Temp tables query fails in veil2_reset_session()")));
535 if (processed != 1) {
536 /* This should be impossible. */ 538 (errcode(ERRCODE_INTERNAL_ERROR),
539 errmsg(
"Unexpected processing error in " 540 "veil2_reset_session: %d", processed)));
542 if (my_tup.f1 == 0) {
543 /* We have no temp tables, so let's create them. */ 547 else if (my_tup.f1 == 3) {
548 /* We have the expected temp tables - check that access 549 * is properly limited. */ 550 if (my_tup.f2 != 3) {
552 (errcode(ERRCODE_INTERNAL_ERROR),
553 errmsg(
"Unexpected access to temp tables in " 554 "veil2_reset_session"),
555 errdetail(
"This indicates an attempt to bypass " 558 /* Access to temp tables looks kosher. Truncate the 565 (errcode(ERRCODE_INTERNAL_ERROR),
566 errmsg(
"Unexpected count of temp tables in " 567 "veil2_reset_session: %d", my_tup.f1),
568 errdetail(
"This indicates an attempt to bypass " 651 (errcode(ERRCODE_INTERNAL_ERROR),
652 errmsg(
"Attempt to check privileges before call to " 653 "veil2_reset_session.")));
671 static int context_idx = -1;
672 int priv = PG_GETARG_INT32(0);
701 static int context_idx = -1;
703 int priv = PG_GETARG_INT32(0);
704 int accessor_id = PG_GETARG_INT32(1);
708 result =
checkContext(&context_idx, 2, accessor_id, priv);
733 static int context_idx = -1;
735 int priv = PG_GETARG_INT32(0);
736 int scope_type_id = PG_GETARG_INT32(1);
737 int scope_id = PG_GETARG_INT32(2);
741 result =
checkContext(&context_idx, scope_type_id, scope_id, priv);
766 static int global_context_idx = -1;
767 static int given_context_idx = -1;
769 int priv = PG_GETARG_INT32(0);
770 int scope_type_id = PG_GETARG_INT32(1);
771 int scope_id = PG_GETARG_INT32(2);
803 static void *saved_plan = NULL;
807 int priv = PG_GETARG_INT32(0);
808 int scope_type_id = PG_GETARG_INT32(1);
809 int scope_id = PG_GETARG_INT32(2);
810 Oid argtypes[] = {INT4OID, INT4OID, INT4OID};
811 Datum args[] = {Int32GetDatum(priv),
812 Int32GetDatum(scope_type_id),
813 Int32GetDatum(scope_id)};
817 "SPI connect failed in " 818 "veil2_i_have_priv_in_superior_scope()");
821 " from veil2.all_superior_scopes asp" 822 " inner join veil2_session_privileges sp" 823 " on sp.scope_type_id = asp.superior_scope_type_id" 824 " and sp.scope_id = asp.superior_scope_id" 825 " where asp.scope_type_id = $2" 826 " and asp.scope_id = $3" 827 " and sp.privs ? $1",
829 &saved_plan, &result);
832 "SPI finish failed in " 833 "veil2_i_have_priv_in_superior_scope()");
834 result = found && result;
859 static int context_idx = -1;
860 static void *saved_plan = NULL;
864 int priv = PG_GETARG_INT32(0);
865 int scope_type_id = PG_GETARG_INT32(1);
866 int scope_id = PG_GETARG_INT32(2);
867 Oid argtypes[] = {INT4OID, INT4OID, INT4OID};
868 Datum args[] = {Int32GetDatum(priv),
869 Int32GetDatum(scope_type_id),
870 Int32GetDatum(scope_id)};
874 /* Start by checking priv in scope - this can maybe save us a 877 result =
checkContext(&context_idx, scope_type_id, scope_id, priv);
881 "SPI connect failed in " 882 "veil2_i_have_priv_in_scope_or_superior()");
885 " from veil2.all_superior_scopes asp" 886 " inner join veil2_session_privileges sp" 887 " on sp.scope_type_id = asp.superior_scope_type_id" 888 " and sp.scope_id = asp.superior_scope_id" 889 " where asp.scope_type_id = $2" 890 " and asp.scope_id = $3" 891 " and sp.privs ? $1",
893 &saved_plan, &result);
896 "SPI finish failed in " 897 "veil2_i_have_priv_in_scope_or_superior()");
898 result = found && result;
926 static int global_context_idx = -1;
927 static int given_context_idx = -1;
928 static void *saved_plan = NULL;
932 int priv = PG_GETARG_INT32(0);
933 int scope_type_id = PG_GETARG_INT32(1);
934 int scope_id = PG_GETARG_INT32(2);
935 Oid argtypes[] = {INT4OID, INT4OID, INT4OID};
936 Datum args[] = {Int32GetDatum(priv),
937 Int32GetDatum(scope_type_id),
938 Int32GetDatum(scope_id)};
948 "SPI connect failed in " 949 "veil2_i_have_priv_in_scope_or_superior()");
952 " from veil2.all_superior_scopes asp" 953 " inner join veil2_session_privileges sp" 954 " on sp.scope_type_id = asp.superior_scope_type_id" 955 " and sp.scope_id = asp.superior_scope_id" 956 " where asp.scope_type_id = $2" 957 " and asp.scope_id = $3" 958 " and sp.privs ? $1",
960 &saved_plan, &result);
963 "SPI finish failed in " 964 "veil2_i_have_priv_in_scope_or_superior()");
965 result = found && result;
982 /* We only return positive integers. That's just the way it 984 Datum results[2] = {Int32GetDatum(
result_counts[0] & INT_MAX),
986 bool nulls[2] = {
false,
false};
987 TupleDesc tuple_desc;
989 if (get_call_result_type(fcinfo, NULL,
990 &tuple_desc) != TYPEFUNC_COMPOSITE) {
992 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
993 errmsg(
"function returning record called in context " 994 "that cannot accept type record")));
996 tuple_desc = BlessTupleDesc(tuple_desc);
997 tuple = heap_form_tuple(tuple_desc, results, nulls);
998 return HeapTupleGetDatum(tuple);
1011 int len = strlen(in);
1012 text *out = palloc(len + VARHDRSZ);
1013 memcpy(VARDATA(out), in, len);
1014 SET_VARSIZE(out, (len + VARHDRSZ));
Datum veil2_datapath(FunctionCallInfo fcinfo)
#define CONTEXT_PRIVS_SIZE(elems)
Datum veil2_reset_session_privs(FunctionCallInfo fcinfo)
ContextPrivs context_privs[0]
static int result_counts[]
static bool fetch_scope_privs(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
Main header file for veil2.
static void do_load_session_privs()
Datum veil2_i_have_priv_in_scope_or_global(FunctionCallInfo fcinfo)
static void clear_session_privs()
static SessionPrivs * extendSessionPrivs(SessionPrivs *session_privs)
void veil2_spi_finish(bool pushed, const char *msg)
Datum veil2_i_have_priv_in_scope_or_superior_or_global(FunctionCallInfo fcinfo)
Datum veil2_true(FunctionCallInfo fcinfo)
static void findContext(int *p_idx, int scope_type, int scope)
static void truncate_temp_tables(bool clear_context)
static bool fetch_2ints(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
static bool checkContext(int *p_idx, int scope_type, int scope, int priv)
Datum veil2_session_ready(FunctionCallInfo fcinfo)
Datum veil2_i_have_priv_in_scope_or_superior(FunctionCallInfo fcinfo)
static void create_temp_tables()
Datum veil2_i_have_global_priv(FunctionCallInfo fcinfo)
static text * textfromstr(char *in)
static void add_scope_privs(int scope_type, int scope, Bitmap *privs)
#define CONTEXT_PRIVS_INCREMENT
static bool checkSessionReady()
bool veil2_bool_from_query(const char *qry, int nargs, Oid *argtypes, Datum *args, void **saved_plan, bool *result)
static void freeContextPrivs(ContextPrivs *cp)
Datum veil2_reset_session(FunctionCallInfo fcinfo)
Datum veil2_i_have_priv_in_scope(FunctionCallInfo fcinfo)
Datum veil2_result_counts(FunctionCallInfo fcinfo)
static void do_reset_session(bool clear_context)
Datum veil2_docpath(FunctionCallInfo fcinfo)
static SessionPrivs * session_privs
int veil2_query(const char *qry, int nargs, Oid *argtypes, Datum *args, bool read_only, void **saved_plan, Fetch_fn process_row, void *fn_param)
static bool error_if_no_session()
void veil2_spi_connect(bool *p_pushed, const char *msg)
static bool session_privs_loaded
Datum veil2_i_have_personal_priv(FunctionCallInfo fcinfo)
Datum veil2_i_have_priv_in_superior_scope(FunctionCallInfo fcinfo)
static bool session_ready