Veil2
Postgres extension for VPD implementations
veil2.c
Go to the documentation of this file.
1 
15 #include "postgres.h"
16 #include "funcapi.h"
17 #include "catalog/pg_type.h"
18 #include "access/xact.h"
19 #include "executor/spi.h"
20 #include "utils/builtins.h"
21 #include "veil2.h"
22 
23 PG_MODULE_MAGIC;
24 
25 
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.
29  */
30 PG_FUNCTION_INFO_V1(veil2_session_ready);
31 PG_FUNCTION_INFO_V1(veil2_reset_session);
32 PG_FUNCTION_INFO_V1(veil2_reset_session_privs);
33 PG_FUNCTION_INFO_V1(veil2_true);
34 PG_FUNCTION_INFO_V1(veil2_i_have_global_priv);
35 PG_FUNCTION_INFO_V1(veil2_i_have_personal_priv);
36 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_scope);
37 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_scope_or_global);
38 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_superior_scope);
39 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_scope_or_superior);
41 PG_FUNCTION_INFO_V1(veil2_result_counts);
42 PG_FUNCTION_INFO_V1(veil2_docpath);
43 PG_FUNCTION_INFO_V1(veil2_datapath);
44 
45 
60 static bool session_ready = false;
61 
62 
67 static int result_counts[] = {0, 0};
68 
69 
74 typedef struct {
76  int scope;
77  Bitmap *privileges;
78 } ContextPrivs;
79 
83 typedef struct {
86  int array_len;
89  ContextPrivs context_privs[0];
90 } SessionPrivs;
91 
92 
96 static SessionPrivs *session_privs = NULL;
97 
101 static bool session_privs_loaded = false;
102 
103 
119 static void
120 findContext(int *p_idx, int scope_type, int scope)
121 {
122  int this = *p_idx;
123  int cmp;
124  int lower = 0;
125  int upper = session_privs->active_contexts - 1;
126  ContextPrivs *this_cp;
127 
128  if (upper == 0) {
129  *p_idx = -1;
130  return;
131  }
132  else if ((this < 0) || (this >= upper)) {
133  /* Create a new start, in the middle of the contexts. */
134  this = upper >> 1;
135  }
136  /* Bsearch until we find a match or realise there is none. */
137  while (true) {
138  this_cp = &(session_privs->context_privs[this]);
139  cmp = this_cp->scope_type - scope_type;
140  if (!cmp) {
141  cmp = this_cp->scope - scope;
142  }
143  if (!cmp) {
144  *p_idx = this;
145  return;
146  }
147  if (cmp > 0) {
148  /* We are looking for a lower value. */
149  upper = this - 1;
150  }
151  else {
152  lower = this + 1;
153  }
154  if (upper < lower) {
155  *p_idx = -1;
156  return;
157  }
158  this = (upper + lower) >> 1;
159  }
160 }
161 
182 static bool
183 checkContext(int *p_idx, int scope_type, int scope, int priv)
184 {
185  findContext(p_idx, scope_type, scope);
186  if (*p_idx == -1) {
187  return false;
188  }
189  return bitmapTestbit(
190  session_privs->context_privs[*p_idx].privileges, priv);
191 }
192 
193 
200 static void
202 {
203  pfree((void *) cp->privileges);
204  cp->privileges = NULL;
205 }
206 
207 
211 static void
213 {
214  int i;
215  if (session_privs) {
216  for (i = session_privs->active_contexts - 1; i >= 0; i--) {
217  freeContextPrivs(&session_privs->context_privs[i]);
218  }
219  session_privs->active_contexts = 0;
220  session_privs_loaded = false;
221  }
222 }
223 
228 #define CONTEXT_PRIVS_INCREMENT 16
229 
235 #define CONTEXT_PRIVS_SIZE(elems) ( \
236  sizeof(SessionPrivs) + \
237  (sizeof(ContextPrivs) * \
238  (elems + CONTEXT_PRIVS_INCREMENT)))
239 
240 /*
241  * Create or extend our SessionPrivs structure.
242  *
243  * @result The newly allocated SessionPrivs struct.
244  */
245 static SessionPrivs *
247 {
248  size_t size;
249  int i;
250  if (session_privs) {
251  size = CONTEXT_PRIVS_SIZE(session_privs->array_len);
252  session_privs = (SessionPrivs *)
253  realloc((void *) session_privs, size);
254  session_privs->array_len += CONTEXT_PRIVS_INCREMENT;
255  for (i = session_privs->array_len - CONTEXT_PRIVS_INCREMENT;
256  i < session_privs->array_len; i++)
257  {
258  session_privs->context_privs[i].privileges = NULL;
259  }
260  }
261  else {
262  session_privs = (SessionPrivs *) calloc(1, CONTEXT_PRIVS_SIZE(0));
263  session_privs->array_len = CONTEXT_PRIVS_INCREMENT;
264  }
265  if (!session_privs) {
266  ereport(ERROR,
267  (errcode(ERRCODE_INTERNAL_ERROR),
268  errmsg("Unable to create session memory in "
269  "extendSessionPrivs()")));
270  }
271  return session_privs;
272 }
273 
274 
282 static void
283 add_scope_privs(int scope_type, int scope, Bitmap *privs)
284 {
285  MemoryContext old_context;
286  int idx = session_privs->active_contexts;
287  if (session_privs->active_contexts >= session_privs->array_len) {
288  session_privs = extendSessionPrivs(session_privs);
289  }
290 
291  session_privs->active_contexts++;
292  session_privs->context_privs[idx].scope_type = scope_type;
293  session_privs->context_privs[idx].scope = scope;
294 
295  /* We copy the bitmap in TopMemoryContext so that it won't be
296  * cleaned-up as transactions come and go. */
297 
298  old_context = MemoryContextSwitchTo(TopMemoryContext);
299  session_privs->context_privs[idx].privileges = bitmapCopy(privs);
300  MemoryContextSwitchTo(old_context);
301 }
302 
303 
317 static bool
318 fetch_scope_privs(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
319 {
320  bool isnull;
321  int scope_type;
322  int scope;
323  Bitmap *privs;
324 
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));
328 
329  add_scope_privs(scope_type, scope, privs);
330  return true;
331 }
332 
337 static void
339 {
340  bool pushed;
341 
342  if (session_privs) {
344  }
345  else {
346  session_privs = extendSessionPrivs(NULL);
347  }
348  veil2_spi_connect(&pushed,
349  "SPI connect failed in do_load_session_privs() - veil2");
350 
351  (void) veil2_query(
352  "select scope_type_id, scope_id, privs"
353  " from veil2_session_privileges"
354  " order by 1, 2",
355  0, NULL, NULL,
356  false, NULL,
357  fetch_scope_privs, NULL);
358 
359  veil2_spi_finish(pushed,
360  "SPI finish failed in do_load_session_privs() - veil2");
361 }
362 
367 static void
369 {
370  if (!session_privs_loaded) {
372  session_privs_loaded = true;
373  }
374 }
375 
386 static bool
388 {
389  static bool init_done = false;
390  static bool error = true;
391  bool pushed;
392  if (!init_done) {
393  veil2_spi_connect(&pushed, "error_if_no_session() (1)");
394  (void) veil2_bool_from_query(
395  "select parameter_value::boolean"
396  " from veil2.system_parameters"
397  " where parameter_name = 'error on uninitialized session'",
398  0, NULL, NULL, NULL, &error);
399  veil2_spi_finish(pushed, "error_if_no_session (2)");
400  init_done = true;
401  }
402  return error;
403 }
404 
405 
406 
421 static bool
422 fetch_2ints(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
423 {
424  bool isnull;
425  tuple_2ints *my_tup = (tuple_2ints *) p_result;
426  my_tup->f1 = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 1, &isnull));
427  my_tup->f2 = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 2, &isnull));
428 
429  return false; // No need to continue processing after this
430 }
431 
432 
437 static void
439 {
440  (void) veil2_query(
441  "create temporary table veil2_session_privileges"
442  " of veil2.session_privileges_t",
443  0, NULL, NULL,
444  false, NULL,
445  NULL, NULL);
446  (void) veil2_query(
447  "create temporary table veil2_ancestor_privileges"
448  " of veil2.session_privileges_t",
449  0, NULL, NULL,
450  false, NULL,
451  NULL, NULL);
452  (void) veil2_query(
453  "create temporary table veil2_session_context"
454  " of veil2.session_context_t",
455  0, NULL, NULL,
456  false, NULL,
457  NULL, NULL);
458 }
459 
460 
469 static void
470 truncate_temp_tables(bool clear_context)
471 {
472  (void) veil2_query(
473  "delete from veil2_session_privileges",
474  0, NULL, NULL,
475  false, NULL,
476  NULL, NULL);
477  if (clear_context) {
478  (void) veil2_query(
479  "delete from veil2_session_context",
480  0, NULL, NULL,
481  false, NULL,
482  NULL, NULL);
483  }
484 }
485 
486 
495 Datum
496 veil2_session_ready(PG_FUNCTION_ARGS)
497 {
498  PG_RETURN_BOOL(session_ready);
499 }
500 
501 
508 static void
509 do_reset_session(bool clear_context)
510 {
511  tuple_2ints my_tup;
512  int processed;
513 
514  processed = veil2_query(
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)",
524  0, NULL, NULL,
525  false, NULL,
526  fetch_2ints, (void *) &my_tup);
527 
528  if (processed == 0) {
529  /* Unexpected error in query. */
530  ereport(ERROR,
531  (errcode(ERRCODE_INTERNAL_ERROR),
532  errmsg("Temp tables query fails in veil2_reset_session()")));
533  }
534  else {
535  if (processed != 1) {
536  /* This should be impossible. */
537  ereport(ERROR,
538  (errcode(ERRCODE_INTERNAL_ERROR),
539  errmsg("Unexpected processing error in "
540  "veil2_reset_session: %d", processed)));
541  }
542  if (my_tup.f1 == 0) {
543  /* We have no temp tables, so let's create them. */
545  session_ready = true;
546  }
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) {
551  ereport(ERROR,
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 "
556  "VPD security!")));
557  }
558  /* Access to temp tables looks kosher. Truncate the
559  * tables. */
560  truncate_temp_tables(clear_context);
561  session_ready = true;
562  }
563  else {
564  ereport(ERROR,
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 "
569  "VPD security!")));
570  }
571  }
572 }
573 
587 Datum
588 veil2_reset_session(PG_FUNCTION_ARGS)
589 {
590  bool pushed;
591 
592  session_ready = false;
594  veil2_spi_connect(&pushed, "failed to reset session (1)");
595  do_reset_session(true);
596  veil2_spi_finish(pushed, "failed to reset session (2)");
597  PG_RETURN_VOID();
598 }
599 
608 Datum
609 veil2_reset_session_privs(PG_FUNCTION_ARGS)
610 {
611  bool pushed;
612 
614  veil2_spi_connect(&pushed, "failed to reset session privs (1)");
615  do_reset_session(false);
616  veil2_spi_finish(pushed, "failed to reset session privs (2)");
617  PG_RETURN_VOID();
618 }
619 
629 Datum
630 veil2_true(PG_FUNCTION_ARGS)
631 {
632  return true;
633 }
634 
643 static bool
645 {
646  if (session_ready) {
647  return true;
648  }
649  if (error_if_no_session()) {
650  ereport(ERROR,
651  (errcode(ERRCODE_INTERNAL_ERROR),
652  errmsg("Attempt to check privileges before call to "
653  "veil2_reset_session.")));
654  }
655  return false;
656 }
657 
668 Datum
669 veil2_i_have_global_priv(PG_FUNCTION_ARGS)
670 {
671  static int context_idx = -1;
672  int priv = PG_GETARG_INT32(0);
673  bool result;
674 
675  if ((result = checkSessionReady())) {
676  load_privs();
677  result = checkContext(&context_idx, 1, 0, priv);
678  }
679  result_counts[result]++;
680  return result;
681 }
682 
683 
698 Datum
699 veil2_i_have_personal_priv(PG_FUNCTION_ARGS)
700 {
701  static int context_idx = -1;
702  bool result;
703  int priv = PG_GETARG_INT32(0);
704  int accessor_id = PG_GETARG_INT32(1);
705 
706  if ((result = checkSessionReady())) {
707  load_privs();
708  result = checkContext(&context_idx, 2, accessor_id, priv);
709  }
710  result_counts[result]++;
711  return result;
712 }
713 
714 
730 Datum
731 veil2_i_have_priv_in_scope(PG_FUNCTION_ARGS)
732 {
733  static int context_idx = -1;
734  bool result;
735  int priv = PG_GETARG_INT32(0);
736  int scope_type_id = PG_GETARG_INT32(1);
737  int scope_id = PG_GETARG_INT32(2);
738 
739  if ((result = checkSessionReady())) {
740  load_privs();
741  result = checkContext(&context_idx, scope_type_id, scope_id, priv);
742  }
743  result_counts[result]++;
744  return result;
745 }
746 
747 
763 Datum
765 {
766  static int global_context_idx = -1;
767  static int given_context_idx = -1;
768  bool result;
769  int priv = PG_GETARG_INT32(0);
770  int scope_type_id = PG_GETARG_INT32(1);
771  int scope_id = PG_GETARG_INT32(2);
772 
773  if ((result = checkSessionReady())) {
774  load_privs();
775  result =
776  (checkContext(&global_context_idx, 1, 0, priv) ||
777  checkContext(&given_context_idx, scope_type_id,
778  scope_id, priv));
779  }
780  result_counts[result]++;
781  return result;
782 }
783 
784 
800 Datum
802 {
803  static void *saved_plan = NULL;
804  bool result;
805  bool found;
806  bool pushed;
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)};
814 
815  if ((result = checkSessionReady())) {
816  veil2_spi_connect(&pushed,
817  "SPI connect failed in "
818  "veil2_i_have_priv_in_superior_scope()");
819  found = veil2_bool_from_query(
820  "select true"
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",
828  3, argtypes, args,
829  &saved_plan, &result);
830 
831  veil2_spi_finish(pushed,
832  "SPI finish failed in "
833  "veil2_i_have_priv_in_superior_scope()");
834  result = found && result;
835  }
836  result_counts[result]++;
837  return result;
838 }
839 
840 
856 Datum
858 {
859  static int context_idx = -1;
860  static void *saved_plan = NULL;
861  bool result;
862  bool found;
863  bool pushed;
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)};
871 
872  if ((result = checkSessionReady())) {
873  load_privs();
874  /* Start by checking priv in scope - this can maybe save us a
875  * query. */
876 
877  result = checkContext(&context_idx, scope_type_id, scope_id, priv);
878 
879  if (!result) {
880  veil2_spi_connect(&pushed,
881  "SPI connect failed in "
882  "veil2_i_have_priv_in_scope_or_superior()");
883  found = veil2_bool_from_query(
884  "select true"
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",
892  3, argtypes, args,
893  &saved_plan, &result);
894 
895  veil2_spi_finish(pushed,
896  "SPI finish failed in "
897  "veil2_i_have_priv_in_scope_or_superior()");
898  result = found && result;
899  }
900  }
901  result_counts[result]++;
902  return result;
903 }
904 
905 
923 Datum
925 {
926  static int global_context_idx = -1;
927  static int given_context_idx = -1;
928  static void *saved_plan = NULL;
929  bool result;
930  bool found;
931  bool pushed;
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)};
939 
940  if ((result = checkSessionReady())) {
941  load_privs();
942  result =
943  (checkContext(&global_context_idx, 1, 0, priv) ||
944  checkContext(&given_context_idx, scope_type_id,
945  scope_id, priv));
946  if (!result) {
947  veil2_spi_connect(&pushed,
948  "SPI connect failed in "
949  "veil2_i_have_priv_in_scope_or_superior()");
950  found = veil2_bool_from_query(
951  "select true"
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",
959  3, argtypes, args,
960  &saved_plan, &result);
961 
962  veil2_spi_finish(pushed,
963  "SPI finish failed in "
964  "veil2_i_have_priv_in_scope_or_superior()");
965  result = found && result;
966  }
967  }
968  result_counts[result]++;
969  return result;
970 }
971 
972 
979 Datum
980 veil2_result_counts(PG_FUNCTION_ARGS)
981 {
982  /* We only return positive integers. That's just the way it
983  * is. */
984  Datum results[2] = {Int32GetDatum(result_counts[0] & INT_MAX),
985  Int32GetDatum(result_counts[1] & INT_MAX)};
986  bool nulls[2] = {false, false};
987  TupleDesc tuple_desc;
988  HeapTuple tuple;
989  if (get_call_result_type(fcinfo, NULL,
990  &tuple_desc) != TYPEFUNC_COMPOSITE) {
991  ereport(ERROR,
992  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
993  errmsg("function returning record called in context "
994  "that cannot accept type record")));
995  }
996  tuple_desc = BlessTupleDesc(tuple_desc);
997  tuple = heap_form_tuple(tuple_desc, results, nulls);
998  return HeapTupleGetDatum(tuple);
999 }
1000 
1008 static text *
1009 textfromstr(char *in)
1010 {
1011  int len = strlen(in);
1012  text *out = palloc(len + VARHDRSZ);
1013  memcpy(VARDATA(out), in, len);
1014  SET_VARSIZE(out, (len + VARHDRSZ));
1015 
1016  return out;
1017 }
1018 
1024 Datum
1025 veil2_docpath(PG_FUNCTION_ARGS)
1026 {
1027  PG_RETURN_TEXT_P(textfromstr(DOCS_PATH));
1028 }
1029 
1036 Datum
1037 veil2_datapath(PG_FUNCTION_ARGS)
1038 {
1039  PG_RETURN_TEXT_P(textfromstr(DATA_PATH));
1040 }
1041 
1042 
Datum veil2_datapath(FunctionCallInfo fcinfo)
Definition: veil2.c:1037
#define CONTEXT_PRIVS_SIZE(elems)
Definition: veil2.c:235
Datum veil2_reset_session_privs(FunctionCallInfo fcinfo)
Definition: veil2.c:609
ContextPrivs context_privs[0]
Definition: veil2.c:89
int active_contexts
Definition: veil2.c:88
static int result_counts[]
Definition: veil2.c:67
static bool fetch_scope_privs(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
Definition: veil2.c:318
#define DOCS_PATH
Definition: veil2.h:84
Main header file for veil2.
static void do_load_session_privs()
Definition: veil2.c:338
Datum veil2_i_have_priv_in_scope_or_global(FunctionCallInfo fcinfo)
Definition: veil2.c:764
int f1
Definition: veil2.h:30
static void clear_session_privs()
Definition: veil2.c:212
static SessionPrivs * extendSessionPrivs(SessionPrivs *session_privs)
Definition: veil2.c:246
void veil2_spi_finish(bool pushed, const char *msg)
Definition: query.c:66
Datum veil2_i_have_priv_in_scope_or_superior_or_global(FunctionCallInfo fcinfo)
Definition: veil2.c:924
Datum veil2_true(FunctionCallInfo fcinfo)
Definition: veil2.c:630
static void findContext(int *p_idx, int scope_type, int scope)
Definition: veil2.c:120
#define DATA_PATH
Definition: veil2.h:88
static void truncate_temp_tables(bool clear_context)
Definition: veil2.c:470
static bool fetch_2ints(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
Definition: veil2.c:422
static bool checkContext(int *p_idx, int scope_type, int scope, int priv)
Definition: veil2.c:183
Datum veil2_session_ready(FunctionCallInfo fcinfo)
Definition: veil2.c:496
Datum veil2_i_have_priv_in_scope_or_superior(FunctionCallInfo fcinfo)
Definition: veil2.c:857
static void load_privs()
Definition: veil2.c:368
static void create_temp_tables()
Definition: veil2.c:438
Datum veil2_i_have_global_priv(FunctionCallInfo fcinfo)
Definition: veil2.c:669
static text * textfromstr(char *in)
Definition: veil2.c:1009
int array_len
Definition: veil2.c:86
static void add_scope_privs(int scope_type, int scope, Bitmap *privs)
Definition: veil2.c:283
int scope
Definition: veil2.c:76
#define CONTEXT_PRIVS_INCREMENT
Definition: veil2.c:228
int f2
Definition: veil2.h:32
static bool checkSessionReady()
Definition: veil2.c:644
bool veil2_bool_from_query(const char *qry, int nargs, Oid *argtypes, Datum *args, void **saved_plan, bool *result)
Definition: query.c:267
static void freeContextPrivs(ContextPrivs *cp)
Definition: veil2.c:201
Datum veil2_reset_session(FunctionCallInfo fcinfo)
Definition: veil2.c:588
Datum veil2_i_have_priv_in_scope(FunctionCallInfo fcinfo)
Definition: veil2.c:731
Datum veil2_result_counts(FunctionCallInfo fcinfo)
Definition: veil2.c:980
static void do_reset_session(bool clear_context)
Definition: veil2.c:509
Datum veil2_docpath(FunctionCallInfo fcinfo)
Definition: veil2.c:1025
static SessionPrivs * session_privs
Definition: veil2.c:96
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)
Definition: query.c:218
static bool error_if_no_session()
Definition: veil2.c:387
void veil2_spi_connect(bool *p_pushed, const char *msg)
Definition: query.c:38
int scope_type
Definition: veil2.c:75
static bool session_privs_loaded
Definition: veil2.c:101
Datum veil2_i_have_personal_priv(FunctionCallInfo fcinfo)
Definition: veil2.c:699
Bitmap * privileges
Definition: veil2.c:77
Datum veil2_i_have_priv_in_superior_scope(FunctionCallInfo fcinfo)
Definition: veil2.c:801
static bool session_ready
Definition: veil2.c:60