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 "access/htup_details.h"
21 #include "utils/builtins.h"
22 
23 #include "veil2.h"
24 
25 PG_MODULE_MAGIC;
26 
27 
28 /* These definitions are here rather than immediately preceding the
29  * function declarations themselves as this code seems to confuse
30  * Doxygen's call graph stuff.
31  */
32 PG_FUNCTION_INFO_V1(veil2_session_ready);
33 PG_FUNCTION_INFO_V1(veil2_reset_session);
34 PG_FUNCTION_INFO_V1(veil2_reset_session_privs);
35 PG_FUNCTION_INFO_V1(veil2_session_context);
36 PG_FUNCTION_INFO_V1(veil2_session_privileges);
37 PG_FUNCTION_INFO_V1(veil2_add_session_privileges);
38 PG_FUNCTION_INFO_V1(veil2_update_session_privileges);
39 PG_FUNCTION_INFO_V1(veil2_true);
40 PG_FUNCTION_INFO_V1(veil2_i_have_global_priv);
41 PG_FUNCTION_INFO_V1(veil2_i_have_personal_priv);
42 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_scope);
43 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_scope_or_global);
44 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_superior_scope);
45 PG_FUNCTION_INFO_V1(veil2_i_have_priv_in_scope_or_superior);
47 PG_FUNCTION_INFO_V1(veil2_result_counts);
48 PG_FUNCTION_INFO_V1(veil2_docpath);
49 PG_FUNCTION_INFO_V1(veil2_datapath);
50 PG_FUNCTION_INFO_V1(veil2_version);
51 
52 
67 static bool session_ready = false;
68 
69 
74 static int result_counts[] = {0, 0};
75 
76 
81 typedef struct {
83  int scope;
84  Bitmap *roles;
85  Bitmap *privileges;
87 
91 typedef struct {
94  int array_len;
97  ContextRolePrivs context_roleprivs[0];
99 
100 
106 typedef struct {
107  bool loaded;
109  int64 session_id;
120 
125 
129 static bool session_roleprivs_loaded = false;
130 
131 static SessionContext session_context = {false, 0, 0, 0, 0,
132  0, 0, 0, 0};
133 
134 
150 static void
151 findContext(int *p_idx, int scope_type, int scope)
152 {
153  int this = *p_idx;
154  int cmp;
155  int lower = 0;
156  int upper;
157  ContextRolePrivs *this_cp;
158 
159  if (!session_roleprivs) {
160  *p_idx = -1;
161  return;
162  }
163  upper = session_roleprivs->active_contexts - 1;
164  if (upper == 0) {
165  *p_idx = -1;
166  return;
167  }
168  else if ((this < 0) || (this >= upper)) {
169  /* Create a new start, in the middle of the contexts. */
170  this = upper >> 1;
171  }
172  /* Bsearch until we find a match or realise there is none. */
173  while (true) {
174  this_cp = &(session_roleprivs->context_roleprivs[this]);
175  cmp = this_cp->scope_type - scope_type;
176  if (!cmp) {
177  cmp = this_cp->scope - scope;
178  }
179  if (!cmp) {
180  *p_idx = this;
181  return;
182  }
183  if (cmp > 0) {
184  /* We are looking for a lower value. */
185  upper = this - 1;
186  }
187  else {
188  lower = this + 1;
189  }
190  if (upper < lower) {
191  *p_idx = -1;
192  return;
193  }
194  this = (upper + lower) >> 1;
195  }
196 }
197 
218 static bool
219 checkContext(int *p_idx, int scope_type, int scope, int priv)
220 {
221  findContext(p_idx, scope_type, scope);
222  if (*p_idx == -1) {
223  return false;
224  }
225  return bitmapTestbit(
226  session_roleprivs->context_roleprivs[*p_idx].privileges, priv);
227 }
228 
229 
236 static void
238 {
239  pfree((void *) cp->roles);
240  pfree((void *) cp->privileges);
241  cp->roles = NULL;
242  cp->privileges = NULL;
243 }
244 
245 
249 static void
251 {
252  int i;
253  MemoryContext old_context;
254  old_context = MemoryContextSwitchTo(TopMemoryContext);
255 
256  if (session_roleprivs) {
257  for (i = session_roleprivs->active_contexts - 1; i >= 0; i--) {
258  freeContextRolePrivs(&session_roleprivs->context_roleprivs[i]);
259  }
260  session_roleprivs->active_contexts = 0;
261  session_roleprivs_loaded = false;
262  }
263  MemoryContextSwitchTo(old_context);
264 }
265 
270 #define CONTEXT_ROLEPRIVS_INCREMENT 16
271 
277 #define CONTEXT_ROLEPRIVS_SIZE(elems) ( \
278  sizeof(SessionRolePrivs) + \
279  (sizeof(ContextRolePrivs) * \
280  (elems + CONTEXT_ROLEPRIVS_INCREMENT)))
281 
282 /*
283  * Create or extend our SessionRolePrivs structure.
284  *
285  * @param session_roleprivs, the current version of the struct, or
286  * NULL, if it has not yet been created.
287  * @result The newly allocated or extended SessionRolePrivs struct.
288  */
289 static SessionRolePrivs *
291 {
292  size_t size;
293  int i;
294  if (session_roleprivs) {
295  size = CONTEXT_ROLEPRIVS_SIZE(session_roleprivs->array_len);
296  session_roleprivs = (SessionRolePrivs *)
297  realloc((void *) session_roleprivs, size);
298  session_roleprivs->array_len += CONTEXT_ROLEPRIVS_INCREMENT;
299  for (i = session_roleprivs->array_len - CONTEXT_ROLEPRIVS_INCREMENT;
300  i < session_roleprivs->array_len; i++)
301  {
302  session_roleprivs->context_roleprivs[i].privileges = NULL;
303  }
304  }
305  else {
306  session_roleprivs = (SessionRolePrivs *)
307  calloc(1, CONTEXT_ROLEPRIVS_SIZE(0));
308  session_roleprivs->array_len = CONTEXT_ROLEPRIVS_INCREMENT;
309  }
310  if (!session_roleprivs) {
311  ereport(ERROR,
312  (errcode(ERRCODE_INTERNAL_ERROR),
313  errmsg("Unable to create session memory in "
314  "extendSessionPrivs()")));
315  }
316  return session_roleprivs;
317 }
318 
319 
328 static void
329 add_scope_roleprivs(int scope_type, int scope, Bitmap *roles, Bitmap *privs)
330 {
331  MemoryContext old_context;
332  int idx;
333 
334  if (!session_roleprivs) {
335  session_roleprivs = extendSessionRolePrivs(NULL);
336  }
337  else if (session_roleprivs->active_contexts >=
338  session_roleprivs->array_len) {
339  session_roleprivs = extendSessionRolePrivs(session_roleprivs);
340  }
341  idx = session_roleprivs->active_contexts;
342  session_roleprivs->active_contexts++;
343  session_roleprivs->context_roleprivs[idx].scope_type = scope_type;
344  session_roleprivs->context_roleprivs[idx].scope = scope;
345 
346  /* We copy the bitmaps in TopMemoryContext so they won't be
347  * cleaned-up as transactions come and go. */
348 
349  old_context = MemoryContextSwitchTo(TopMemoryContext);
350  session_roleprivs->context_roleprivs[idx].roles = bitmapCopy(roles);
351  session_roleprivs->context_roleprivs[idx].privileges = bitmapCopy(privs);
352  MemoryContextSwitchTo(old_context);
353 }
354 
364 static void
365 update_scope_roleprivs(int scope_type, int scope, Bitmap *roles, Bitmap *privs)
366 {
367  int idx;
368  MemoryContext old_context;
369 
370  findContext(&idx, scope_type, scope);
371  if (idx == -1) {
372  /* PK fields do not match an existing record, so the update
373  * does nothing. */
374  return;
375  }
376  old_context = MemoryContextSwitchTo(TopMemoryContext);
377  freeContextRolePrivs(&session_roleprivs->context_roleprivs[idx]);
378  session_roleprivs->context_roleprivs[idx].roles = bitmapCopy(roles);
379  session_roleprivs->context_roleprivs[idx].privileges = bitmapCopy(privs);
380  MemoryContextSwitchTo(old_context);
381 }
382 
383 
394 static bool
396 {
397  static bool init_done = false;
398  static bool error = true;
399  bool pushed;
400  if (!init_done) {
401  veil2_spi_connect(&pushed, "error_if_no_session() (1)");
402  (void) veil2_bool_from_query(
403  "select parameter_value::boolean"
404  " from veil2.system_parameters"
405  " where parameter_name = 'error on uninitialized session'",
406  0, NULL, NULL, NULL, &error);
407  veil2_spi_finish(pushed, "error_if_no_session (2)");
408  init_done = true;
409  }
410  return error;
411 }
412 
427 static bool
428 fetch_2ints(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
429 {
430  bool isnull;
431  tuple_2ints *my_tup = (tuple_2ints *) p_result;
432  my_tup->f1 = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 1, &isnull));
433  my_tup->f2 = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 2, &isnull));
434 
435  return false; // No need to continue processing after this
436 }
437 
438 
444 static void
446 {
447  (void) veil2_query(
448  "create temporary table veil2_ancestor_privileges"
449  " of veil2.session_privileges_t",
450  0, NULL, NULL,
451  false, NULL,
452  NULL, NULL);
453 }
454 
455 
462 static void
463 do_reset_session(bool clear_context)
464 {
465  tuple_2ints my_tup;
466  int processed;
467 
468  processed = veil2_query(
469  "select count(*)::integer,"
470  " sum(case when c.relacl is null then 1 else 0 end)"
471  " from pg_catalog.pg_class c"
472  " where c.relname = 'veil2_ancestor_privileges'"
473  " and c.relkind = 'r'"
474  " and c.relpersistence = 't'"
475  " and pg_catalog.pg_table_is_visible(c.oid)",
476  0, NULL, NULL,
477  false, NULL,
478  fetch_2ints, (void *) &my_tup);
479 
480  if (processed == 0) {
481  /* Unexpected error in query. */
482  ereport(ERROR,
483  (errcode(ERRCODE_INTERNAL_ERROR),
484  errmsg("Temp tables query fails in veil2_reset_session()")));
485  }
486  else {
487  if (processed != 1) {
488  /* This should be impossible. */
489  ereport(ERROR,
490  (errcode(ERRCODE_INTERNAL_ERROR),
491  errmsg("Unexpected processing error in "
492  "veil2_reset_session: %d", processed)));
493  }
494  if (my_tup.f1 == 0) {
495  /* We have no temp table, so let's create it. */
497  session_ready = true;
498  }
499  else if (my_tup.f1 == 1) {
500  /* We have the expected temp tables - check that access
501  * is properly limited. */
502  if (my_tup.f2 != 1) {
503  ereport(ERROR,
504  (errcode(ERRCODE_INTERNAL_ERROR),
505  errmsg("Unexpected access to temp table in "
506  "veil2_reset_session"),
507  errdetail("This indicates an attempt to bypass "
508  "VPD security!")));
509  }
510  /* Access to temp tables looks kosher. Truncate the
511  * tables. */
512  if (clear_context) {
513  session_context.loaded = false;
514  }
516  session_ready = true;
517  }
518  else {
519  ereport(ERROR,
520  (errcode(ERRCODE_INTERNAL_ERROR),
521  errmsg("Unexpected count of temp tables in "
522  "veil2_reset_session: %d", my_tup.f1),
523  errdetail("This indicates an attempt to bypass "
524  "VPD security!")));
525  }
526  }
527 }
528 
529 
538 Datum
539 veil2_session_ready(PG_FUNCTION_ARGS)
540 {
541  PG_RETURN_BOOL(session_ready);
542 }
543 
544 
558 Datum
559 veil2_reset_session(PG_FUNCTION_ARGS)
560 {
561  bool pushed;
562 
563  session_ready = false;
564  veil2_spi_connect(&pushed, "failed to reset session (1)");
565  do_reset_session(true);
566  veil2_spi_finish(pushed, "failed to reset session (2)");
567  PG_RETURN_VOID();
568 }
569 
578 Datum
579 veil2_reset_session_privs(PG_FUNCTION_ARGS)
580 {
581  bool pushed;
582 
583  veil2_spi_connect(&pushed, "failed to reset session privs (1)");
584  do_reset_session(false);
585  veil2_spi_finish(pushed, "failed to reset session privs (2)");
586  PG_RETURN_VOID();
587 }
588 
597 Datum
598 veil2_session_context(PG_FUNCTION_ARGS)
599 {
600  Datum results[9];
601  static bool allnulls[9] = {true, true, true, true,
602  true, true, true, true, true};
603  static bool nonulls[9] = {false, false, false, false,
604  false, false, false, false, false};
605  bool *nulls;
606  TupleDesc tuple_desc;
607  HeapTuple tuple;
608  if (get_call_result_type(fcinfo, NULL,
609  &tuple_desc) != TYPEFUNC_COMPOSITE) {
610  ereport(ERROR,
611  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
612  errmsg("function returning record called in context "
613  "that cannot accept type record")));
614  }
615  tuple_desc = BlessTupleDesc(tuple_desc);
616 
617  if (!PG_ARGISNULL(0)) {
618  session_context.accessor_id = PG_GETARG_INT32(0);
619  session_context.session_id = PG_GETARG_INT64(1);
620  session_context.login_context_type_id = PG_GETARG_INT32(2);
621  session_context.login_context_id = PG_GETARG_INT32(3);
622  session_context.session_context_type_id = PG_GETARG_INT32(4);
623  session_context.session_context_id = PG_GETARG_INT32(5);
624  session_context.mapping_context_type_id = PG_GETARG_INT32(6);
625  session_context.mapping_context_id = PG_GETARG_INT32(7);
626  if (PG_ARGISNULL(8)) {
627  session_context.parent_session_id = session_context.session_id;
628  }
629  else {
630  session_context.parent_session_id = PG_GETARG_INT64(8);
631  }
632  session_context.loaded = true;
633  }
634  if (session_context.loaded) {
635  results[0] = Int32GetDatum(session_context.accessor_id);
636  results[1] = Int64GetDatum(session_context.session_id);
637  results[2] = Int32GetDatum(session_context.login_context_type_id);
638  results[3] = Int32GetDatum(session_context.login_context_id);
639  results[4] = Int32GetDatum(session_context.session_context_type_id);
640  results[5] = Int32GetDatum(session_context.session_context_id);
641  results[6] = Int32GetDatum(session_context.mapping_context_type_id);
642  results[7] = Int32GetDatum(session_context.mapping_context_id);
643  nulls = nonulls;
644  if (session_context.parent_session_id ==
645  session_context.session_id)
646  {
647  nulls[8] = true;
648  }
649  else {
650  results[8] = Int64GetDatum(session_context.parent_session_id);
651  nulls[8] = false;
652  }
653  }
654  else {
655  nulls = allnulls;
656  }
657  tuple = heap_form_tuple(tuple_desc, results, nulls);
658  tuple_desc = BlessTupleDesc(tuple_desc);
659  return HeapTupleGetDatum(tuple);
660 }
661 
662 
671 Datum
672 veil2_session_privileges(PG_FUNCTION_ARGS)
673 {
674  FuncCallContext *funcctx;
675  AttInMetadata *attinmeta;
676  MemoryContext oldcontext;
677  TupleDesc tupdesc;
678  long idx;
679  bool nulls[4] = {false, false, false, false};
680 
681  if (SRF_IS_FIRSTCALL()) {
682  funcctx = SRF_FIRSTCALL_INIT();
683  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
684 
685  tupdesc = RelationNameGetTupleDesc("veil2.session_privileges_t");
686  funcctx->tuple_desc = tupdesc;
687  attinmeta = TupleDescGetAttInMetadata(tupdesc);
688  funcctx->attinmeta = attinmeta;
689 
690  MemoryContextSwitchTo(oldcontext);
691  /* We use the user function context to store an index into
692  * session_roleprivs. */
693  funcctx->user_fctx = (void *) 0;
694  }
695 
696  funcctx = SRF_PERCALL_SETUP();
697  idx = (long) funcctx->user_fctx;
698 
699  if (session_roleprivs &&
700  (idx < session_roleprivs->active_contexts)) {
701  Datum results[4];
702  HeapTuple tuple;
703  Datum datum;
704  Bitmap *bitmap;
705  results[0] = Int32GetDatum(session_roleprivs->
706  context_roleprivs[idx].scope_type);
707  results[1] = Int32GetDatum(session_roleprivs->
708  context_roleprivs[idx].scope);
709  bitmap = session_roleprivs->context_roleprivs[idx].roles;
710  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
711  if (bitmap) {
712  results[2] = (Datum) bitmapCopy(bitmap);
713  }
714  else {
715  nulls[2] = true;
716  }
717  bitmap = session_roleprivs->context_roleprivs[idx].privileges;
718  if (bitmap) {
719  results[3] = (Datum) bitmapCopy(bitmap);
720  }
721  else {
722  nulls[3] = true;
723  }
724  MemoryContextSwitchTo(oldcontext);
725  tupdesc = funcctx->tuple_desc;
726  tuple = heap_form_tuple(tupdesc, results, nulls);
727  tupdesc = BlessTupleDesc(tupdesc);
728  datum = TupleGetDatum(tupdesc, tuple);
729  funcctx->user_fctx = (void *) (idx + 1);
730  SRF_RETURN_NEXT(funcctx, datum);
731  }
732  else {
733  SRF_RETURN_DONE(funcctx);
734  }
735 }
736 
751 Datum veil2_add_session_privileges(PG_FUNCTION_ARGS)
752 {
753  int scope_type_id = PG_GETARG_INT32(0);
754  int scope_id = PG_GETARG_INT32(1);
755  Bitmap *roles = PG_GETARG_BITMAP(2);
756  Bitmap *privs = PG_GETARG_BITMAP(3);
757 
758  add_scope_roleprivs(scope_type_id, scope_id, roles, privs);
759  PG_RETURN_VOID();
760 }
761 
762 
775 Datum veil2_update_session_privileges(PG_FUNCTION_ARGS)
776 {
777  int scope_type_id = PG_GETARG_INT32(0);
778  int scope_id = PG_GETARG_INT32(1);
779  Bitmap *roles = PG_GETARG_BITMAP(2);
780  Bitmap *privs = PG_GETARG_BITMAP(3);
781 
782  update_scope_roleprivs(scope_type_id, scope_id, roles, privs);
783  PG_RETURN_VOID();
784 }
785 
795 Datum
796 veil2_true(PG_FUNCTION_ARGS)
797 {
798  return true;
799 }
800 
809 static bool
811 {
812  if (session_ready) {
813  return true;
814  }
815  if (error_if_no_session()) {
816  ereport(ERROR,
817  (errcode(ERRCODE_INTERNAL_ERROR),
818  errmsg("Attempt to check privileges before call to "
819  "veil2_reset_session.")));
820  }
821  return false;
822 }
823 
834 Datum
835 veil2_i_have_global_priv(PG_FUNCTION_ARGS)
836 {
837  static int context_idx = -1;
838  int priv = PG_GETARG_INT32(0);
839  bool result;
840 
841  if ((result = checkSessionReady())) {
842  result = checkContext(&context_idx, 1, 0, priv);
843  }
844  result_counts[result]++;
845  return result;
846 }
847 
848 
863 Datum
864 veil2_i_have_personal_priv(PG_FUNCTION_ARGS)
865 {
866  static int context_idx = -1;
867  bool result;
868  int priv = PG_GETARG_INT32(0);
869  int accessor_id = PG_GETARG_INT32(1);
870 
871  if ((result = checkSessionReady())) {
872  result = checkContext(&context_idx, 2, accessor_id, priv);
873  }
874  result_counts[result]++;
875  return result;
876 }
877 
878 
894 Datum
895 veil2_i_have_priv_in_scope(PG_FUNCTION_ARGS)
896 {
897  static int context_idx = -1;
898  bool result;
899  int priv = PG_GETARG_INT32(0);
900  int scope_type_id = PG_GETARG_INT32(1);
901  int scope_id = PG_GETARG_INT32(2);
902 
903  if ((result = checkSessionReady())) {
904  result = checkContext(&context_idx, scope_type_id, scope_id, priv);
905  }
906  result_counts[result]++;
907  return result;
908 }
909 
910 
926 Datum
928 {
929  static int global_context_idx = -1;
930  static int given_context_idx = -1;
931  bool result;
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 
936  if ((result = checkSessionReady())) {
937  result =
938  (checkContext(&global_context_idx, 1, 0, priv) ||
939  checkContext(&given_context_idx, scope_type_id,
940  scope_id, priv));
941  }
942  result_counts[result]++;
943  return result;
944 }
945 
946 
962 Datum
964 {
965  static void *saved_plan = NULL;
966  bool result;
967  bool found;
968  bool pushed;
969  int priv = PG_GETARG_INT32(0);
970  int scope_type_id = PG_GETARG_INT32(1);
971  int scope_id = PG_GETARG_INT32(2);
972  Oid argtypes[] = {INT4OID, INT4OID, INT4OID};
973  Datum args[] = {Int32GetDatum(priv),
974  Int32GetDatum(scope_type_id),
975  Int32GetDatum(scope_id)};
976 
977  if ((result = checkSessionReady())) {
978  veil2_spi_connect(&pushed,
979  "SPI connect failed in "
980  "veil2_i_have_priv_in_superior_scope()");
981  found = veil2_bool_from_query(
982  "select true"
983  " from veil2.all_superior_scopes asp"
984  " inner join veil2.session_privileges() sp"
985  " on sp.scope_type_id = asp.superior_scope_type_id"
986  " and sp.scope_id = asp.superior_scope_id"
987  " where asp.scope_type_id = $2"
988  " and asp.scope_id = $3"
989  " and sp.privs ? $1",
990  3, argtypes, args,
991  &saved_plan, &result);
992 
993  veil2_spi_finish(pushed,
994  "SPI finish failed in "
995  "veil2_i_have_priv_in_superior_scope()");
996  result = found && result;
997  }
998  result_counts[result]++;
999  return result;
1000 }
1001 
1002 
1018 Datum
1020 {
1021  static int context_idx = -1;
1022  static void *saved_plan = NULL;
1023  bool result;
1024  bool found;
1025  bool pushed;
1026  int priv = PG_GETARG_INT32(0);
1027  int scope_type_id = PG_GETARG_INT32(1);
1028  int scope_id = PG_GETARG_INT32(2);
1029  Oid argtypes[] = {INT4OID, INT4OID, INT4OID};
1030  Datum args[] = {Int32GetDatum(priv),
1031  Int32GetDatum(scope_type_id),
1032  Int32GetDatum(scope_id)};
1033 
1034  if ((result = checkSessionReady())) {
1035  /* Start by checking priv in scope - this can maybe save us a
1036  * query. */
1037 
1038  result = checkContext(&context_idx, scope_type_id, scope_id, priv);
1039 
1040  if (!result) {
1041  veil2_spi_connect(&pushed,
1042  "SPI connect failed in "
1043  "veil2_i_have_priv_in_scope_or_superior()");
1044  found = veil2_bool_from_query(
1045  "select true"
1046  " from veil2.all_superior_scopes asp"
1047  " inner join veil2.session_privileges() sp"
1048  " on sp.scope_type_id = asp.superior_scope_type_id"
1049  " and sp.scope_id = asp.superior_scope_id"
1050  " where asp.scope_type_id = $2"
1051  " and asp.scope_id = $3"
1052  " and sp.privs ? $1",
1053  3, argtypes, args,
1054  &saved_plan, &result);
1055 
1056  veil2_spi_finish(pushed,
1057  "SPI finish failed in "
1058  "veil2_i_have_priv_in_scope_or_superior()");
1059  result = found && result;
1060  }
1061  }
1062  result_counts[result]++;
1063  return result;
1064 }
1065 
1066 
1084 Datum
1086 {
1087  static int global_context_idx = -1;
1088  static int given_context_idx = -1;
1089  static void *saved_plan = NULL;
1090  bool result;
1091  bool found;
1092  bool pushed;
1093  int priv = PG_GETARG_INT32(0);
1094  int scope_type_id = PG_GETARG_INT32(1);
1095  int scope_id = PG_GETARG_INT32(2);
1096  Oid argtypes[] = {INT4OID, INT4OID, INT4OID};
1097  Datum args[] = {Int32GetDatum(priv),
1098  Int32GetDatum(scope_type_id),
1099  Int32GetDatum(scope_id)};
1100 
1101  if ((result = checkSessionReady())) {
1102  result =
1103  (checkContext(&global_context_idx, 1, 0, priv) ||
1104  checkContext(&given_context_idx, scope_type_id,
1105  scope_id, priv));
1106  if (!result) {
1107  veil2_spi_connect(&pushed,
1108  "SPI connect failed in "
1109  "veil2_i_have_priv_in_scope_or_superior()");
1110  found = veil2_bool_from_query(
1111  "select true"
1112  " from veil2.all_superior_scopes asp"
1113  " inner join veil2.session_privileges() sp"
1114  " on sp.scope_type_id = asp.superior_scope_type_id"
1115  " and sp.scope_id = asp.superior_scope_id"
1116  " where asp.scope_type_id = $2"
1117  " and asp.scope_id = $3"
1118  " and sp.privs ? $1",
1119  3, argtypes, args,
1120  &saved_plan, &result);
1121 
1122  veil2_spi_finish(pushed,
1123  "SPI finish failed in "
1124  "veil2_i_have_priv_in_scope_or_superior()");
1125  result = found && result;
1126  }
1127  }
1128  result_counts[result]++;
1129  return result;
1130 }
1131 
1132 
1139 Datum
1140 veil2_result_counts(PG_FUNCTION_ARGS)
1141 {
1142  /* We only return positive integers. That's just the way it
1143  * is. */
1144  Datum results[2] = {Int32GetDatum(result_counts[0] & INT_MAX),
1145  Int32GetDatum(result_counts[1] & INT_MAX)};
1146  bool nulls[2] = {false, false};
1147  TupleDesc tuple_desc;
1148  HeapTuple tuple;
1149  if (get_call_result_type(fcinfo, NULL,
1150  &tuple_desc) != TYPEFUNC_COMPOSITE) {
1151  ereport(ERROR,
1152  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1153  errmsg("function returning record called in context "
1154  "that cannot accept type record")));
1155  }
1156  tuple_desc = BlessTupleDesc(tuple_desc);
1157  tuple = heap_form_tuple(tuple_desc, results, nulls);
1158  return HeapTupleGetDatum(tuple);
1159 }
1160 
1168 static text *
1169 textfromstr(char *in)
1170 {
1171  int len = strlen(in);
1172  text *out = palloc(len + VARHDRSZ);
1173  memcpy(VARDATA(out), in, len);
1174  SET_VARSIZE(out, (len + VARHDRSZ));
1175 
1176  return out;
1177 }
1178 
1184 Datum
1185 veil2_docpath(PG_FUNCTION_ARGS)
1186 {
1187  PG_RETURN_TEXT_P(textfromstr(DOCS_PATH));
1188 }
1189 
1196 Datum
1197 veil2_datapath(PG_FUNCTION_ARGS)
1198 {
1199  PG_RETURN_TEXT_P(textfromstr(DATA_PATH));
1200 }
1201 
1202 
1208 Datum
1209 veil2_version(PG_FUNCTION_ARGS)
1210 {
1211  PG_RETURN_TEXT_P(textfromstr(VEIL2_VERSION));
1212 }
1213 
1214 
static SessionContext session_context
Definition: veil2.c:131
Datum veil2_datapath(FunctionCallInfo fcinfo)
Definition: veil2.c:1197
bool loaded
Definition: veil2.c:107
Datum veil2_reset_session_privs(FunctionCallInfo fcinfo)
Definition: veil2.c:579
int scope_type
Definition: veil2.c:82
int mapping_context_id
Definition: veil2.c:115
static int result_counts[]
Definition: veil2.c:74
#define CONTEXT_ROLEPRIVS_INCREMENT
Definition: veil2.c:270
#define DOCS_PATH
Definition: veil2.h:90
Datum veil2_update_session_privileges(FunctionCallInfo fcinfo)
Definition: veil2.c:775
#define VEIL2_VERSION
Definition: veil2_version.h:14
Main header file for veil2.
Datum veil2_i_have_priv_in_scope_or_global(FunctionCallInfo fcinfo)
Definition: veil2.c:927
int f1
Definition: veil2.h:31
static void freeContextRolePrivs(ContextRolePrivs *cp)
Definition: veil2.c:237
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:1085
Datum veil2_true(FunctionCallInfo fcinfo)
Definition: veil2.c:796
static void findContext(int *p_idx, int scope_type, int scope)
Definition: veil2.c:151
int active_contexts
Definition: veil2.c:96
#define DATA_PATH
Definition: veil2.h:94
static bool fetch_2ints(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
Definition: veil2.c:428
static bool checkContext(int *p_idx, int scope_type, int scope, int priv)
Definition: veil2.c:219
static SessionRolePrivs * extendSessionRolePrivs(SessionRolePrivs *session_roleprivs)
Definition: veil2.c:290
static void add_scope_roleprivs(int scope_type, int scope, Bitmap *roles, Bitmap *privs)
Definition: veil2.c:329
Datum veil2_session_ready(FunctionCallInfo fcinfo)
Definition: veil2.c:539
Datum veil2_i_have_priv_in_scope_or_superior(FunctionCallInfo fcinfo)
Definition: veil2.c:1019
Datum veil2_session_privileges(FunctionCallInfo fcinfo)
Definition: veil2.c:672
static void create_temp_tables()
Definition: veil2.c:445
Datum veil2_i_have_global_priv(FunctionCallInfo fcinfo)
Definition: veil2.c:835
static text * textfromstr(char *in)
Definition: veil2.c:1169
int session_context_id
Definition: veil2.c:113
int login_context_id
Definition: veil2.c:111
int64 parent_session_id
Definition: veil2.c:118
Datum veil2_add_session_privileges(FunctionCallInfo fcinfo)
Definition: veil2.c:751
Datum veil2_session_context(FunctionCallInfo fcinfo)
Definition: veil2.c:598
int f2
Definition: veil2.h:33
static SessionRolePrivs * session_roleprivs
Definition: veil2.c:124
static bool checkSessionReady()
Definition: veil2.c:810
Bitmap * privileges
Definition: veil2.c:85
bool veil2_bool_from_query(const char *qry, int nargs, Oid *argtypes, Datum *args, void **saved_plan, bool *result)
Definition: query.c:267
int login_context_type_id
Definition: veil2.c:110
ContextRolePrivs context_roleprivs[0]
Definition: veil2.c:97
int accessor_id
Definition: veil2.c:108
Datum veil2_reset_session(FunctionCallInfo fcinfo)
Definition: veil2.c:559
#define CONTEXT_ROLEPRIVS_SIZE(elems)
Definition: veil2.c:277
Bitmap * roles
Definition: veil2.c:84
Datum veil2_i_have_priv_in_scope(FunctionCallInfo fcinfo)
Definition: veil2.c:895
Datum veil2_result_counts(FunctionCallInfo fcinfo)
Definition: veil2.c:1140
static void do_reset_session(bool clear_context)
Definition: veil2.c:463
Datum veil2_docpath(FunctionCallInfo fcinfo)
Definition: veil2.c:1185
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
int64 session_id
Definition: veil2.c:109
static bool error_if_no_session()
Definition: veil2.c:395
int array_len
Definition: veil2.c:94
Datum veil2_version(FunctionCallInfo fcinfo)
Definition: veil2.c:1209
int session_context_type_id
Definition: veil2.c:112
static bool session_roleprivs_loaded
Definition: veil2.c:129
static void update_scope_roleprivs(int scope_type, int scope, Bitmap *roles, Bitmap *privs)
Definition: veil2.c:365
void veil2_spi_connect(bool *p_pushed, const char *msg)
Definition: query.c:38
int mapping_context_type_id
Definition: veil2.c:114
static void clear_session_roleprivs()
Definition: veil2.c:250
Datum veil2_i_have_personal_priv(FunctionCallInfo fcinfo)
Definition: veil2.c:864
Datum veil2_i_have_priv_in_superior_scope(FunctionCallInfo fcinfo)
Definition: veil2.c:963
static bool session_ready
Definition: veil2.c:67