Re: SE-PostgreSQL Updated Revision (r1460) - Mailing list pgsql-hackers

From KaiGai Kohei
Subject Re: SE-PostgreSQL Updated Revision (r1460)
Date
Msg-id 497D7055.9090806@ak.jp.nec.com
Whole thread Raw
In response to Re: SE-PostgreSQL Updated Revision (r1460)  (KaiGai Kohei <kaigai@kaigai.gr.jp>)
Responses Re: SE-PostgreSQL Updated Revision (r1460)  (KaiGai Kohei <kaigai@ak.jp.nec.com>)
List pgsql-hackers
Robert,

The attached patch is a draft to replace RedHat/Fedora RPM centric
expressions, to add a reference at "Database Roles and Privileges"
chapter and a bit cleanups for the latest revision (r1467).
In the previous revision, it noted users to check the version of
RPM package, but the revised one notes actually required features.
The version number is rewritten as a hint.

What is your opinion?

Thanks,

KaiGai Kohei wrote:
> Robert Haas wrote:
>> On Fri, Jan 23, 2009 at 12:30 AM, KaiGai Kohei <kaigai@ak.jp.nec.com>
>> wrote:
>>> The patch set of SE-PostgreSQL and related stuff were updated (r1460).
>>>
>>> [1/5]
>>> http://sepgsql.googlecode.com/files/sepostgresql-sepgsql-8.4devel-3-r1460.patch
>>>
>>> [2/5]
>>> http://sepgsql.googlecode.com/files/sepostgresql-utils-8.4devel-3-r1460.patch
>>>
>>> [3/5]
>>> http://sepgsql.googlecode.com/files/sepostgresql-policy-8.4devel-3-r1460.patch
>>>
>>> [4/5]
>>> http://sepgsql.googlecode.com/files/sepostgresql-docs-8.4devel-3-r1460.patch
>>>
>>> [5/5]
>>> http://sepgsql.googlecode.com/files/sepostgresql-tests-8.4devel-3-r1460.patch
>>>
>>
>> KaiGai -
>>
>> I read through your docs patch tonight and did some copy editing.
>> Please see the attached patches, which I hope you will find helpful.
>> I have attached my suggested changes both as a patch against v1460
>> (sepostgresql-docs-rmh-vs-1460.gz) and also as patch against CVS HEAD
>> (sepostgresql-docs-rmh-vs-cvs-head), since I am not sure which is
>> easier for you.  I have a couple of general comments about the
>> documentation:
>
> Thanks your feedbacks!
>
> I basically applied your fixes as is, expect for the following items:
> - You replaced
>   ! Its providing access controls are not _bypassable_ for any clients ...
>     by
>   ! The access controls implemented by SE-PostgrSQL may not be _biased_
> even ...
>
>   I wanted to express it is "unavoidable" here, so I changed as:
>   ! The access controls implemented by SE-PostgrSQL may not be
> _bypassed_ even ...
>
> - I found a typo: "MAC" is described as "MAc".
>
> And, I have a question about documentation manner.
> - You represented "getpeercon()" function as a system call.
>   But, it is actually a wrapper function of getsockopt(2) system call,
>   so the "getpeercon(3)" is not a system call strictly.
>   Is it necessary to represent these stuffs strictly correct?
>   (Thus, I wrote it as "API" in the r1460.)
>
>
>> 1. The docs as written are very Red Hat-centric, even to the point of
>> making reference to specific versions of Red Hat RPMs.  I think that
>> the community will find this unacceptable, as Red Hat is certainly not
>> the only SELinux-enabled distribution and I presume that we want to
>> support all of them to an equal degree.
>
> I guess you pointed out about:
>  1. The "Requirement" section in "Build and Installation" assumes
>     RedHat/Fedora's RPM package and its version number.
>  2. The security context and security policy used to explanation
>     assumes specific security policy.
>  3. "Labeled IPsec" seciton points to "RedHatEL4 Security Guide",
>     and it assumes the racoon's configuration files are deployed
>     as RPM package doing.
>
> About 1, is it necessary to rip the RPM specific version number
> and replace it as:
>   selinux-policy which includes SE-PostgreSQL related stuffs.
>
> About 2, SELinux community provides its default security policy,
> and distributor's policy (including RedHat's one) is a derivative
> of the default policy.
> It is developed independent from distributor's cycle.
>   http://oss.tresys.com/projects/refpolicy
>
> http://oss.tresys.com/repos/refpolicy/trunk/policy/modules/services/postgresql.te
>
>
> You can find some of sepgsql_xxxx identifiers in postgresql.te.
> All the appeared identifiers are upstreamed, so these are not Red Hat
> specific.
>
> About 3, If it rips the link to Red Hat and does not assume specific
> path of "racoon.conf", the explnation become neutral.
>
>
>> 2. Some of the information that is documented here properly belongs in
>> other sections of the documentation.  For example, the information
>> about GUCs clearly belongs somewhere in the section on server
>> configuration where all of the other GUCs are documented, not in a
>> separate sections about SE-PostgreSQL.
>
> These explanations are moved to "Security and Authentication" section
> in "Chapter 18. Server Configuration".
>
>> I suspect that all of the
>> information about row-level ACLs should be ripped out of security.sgml
>> and inserted into an appropriate portion of the "Database Roles and
>> Privileges" chapter, leaving this file to talk just about
>> SE-PostgreSQL.
>
> It is indeed an aspect of row-level ACLs.
> However, it is also a feature on PGACE framework, same as SE-PostgreSQL.
> An idea is to put a reference to indicate the row-level ACLs section
> on "Database Roles and Privileges" chapter, like:
>
>   PostgreSQL has an enhancement of database roles and privileges mechanism
>   which allows to database ACLs in row-level granuality. See, <xref ...>
>   for more details.
>
> What do you think?
>
>> 3. It seems to me that the analogy between SQL DAC and Unix user/group
>> DAC is mentioned far too many times, and there are other cases where
>> information is repeated as well.  I think it might help to reorganize
>> the document a bit so that you introduce concepts in the right order.
>
> Indeed, it was redundant explanation. Thanks for youe edit.
>
>> For example, the section that defines MAC and DAC is a ways down in
>> the document, but you use those terms a whole bunch of times before
>> defining them.  I'm not 100% sure that we even want to be defining MAC
>> and DAC in our documentation, since those are general industry terms
>> that are not PostgreSQL-specific.  But if we are going to define them
>> then we should try to do so in the clearest way possible.
>
> I can add the definitions of terms.
> However, it is unclear whether PostgreSQL documentation should include
> them, or not. For example, wikipedia has enough explanation for their
> generam meanings.
>   http://en.wikipedia.org/wiki/Discretionary_Access_Control
>   http://en.wikipedia.org/wiki/Mandatory_Access_Control
>
> It seems to me "Discretionary Access Control (DAC)" is an enough key
> to search its meaning.
>
>> Overall, I would say there is a fair amount of work left to be done to
>> get this documentation up to par, but it's a good start and I hope
>> that the attached patches and suggestions will be helpful.
>
> I'm glad to see your help.
> I'll pay my efforts for documentations also. But English is not my mother
> language, so any suggestions are helpful for me.
>
> Thanks,


--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
diff -Nrpc base/configure sepgsql/configure
*** base/configure    Fri Jan 23 10:23:37 2009
--- sepgsql/configure    Fri Jan 23 10:55:35 2009
*************** with_libxml
*** 710,715 ****
--- 710,716 ----
  with_libxslt
  with_system_tzdata
  with_zlib
+ enable_selinux
  GREP
  EGREP
  ELF_SYS
*************** Optional Features:
*** 1378,1383 ****
--- 1379,1385 ----
    --enable-thread-safety  make client libraries thread-safe
    --enable-thread-safety-force
                            force thread-safety despite thread test failure
+   --enable-selinux        enable to build with SELinux support
    --disable-float4-byval  disable float4 passed by value
    --disable-float8-byval  disable float8 passed by value
    --disable-largefile     omit support for large files
*************** fi
*** 5531,5536 ****
--- 5533,5644 ----


  #
+ # SELinux support
+ #
+
+ pgac_args="$pgac_args enable_selinux"
+
+ # Check whether --enable-selinux was given.
+ if test "${enable_selinux+set}" = set; then
+   enableval=$enable_selinux;
+   case $enableval in
+     yes)
+       :
+       ;;
+     no)
+       :
+       ;;
+     *)
+       { { echo "$as_me:$LINENO: error: no argument expected for --enable-selinux option" >&5
+ echo "$as_me: error: no argument expected for --enable-selinux option" >&2;}
+    { (exit 1); exit 1; }; }
+       ;;
+   esac
+
+ else
+   enable_selinux=no
+
+ fi
+
+
+ if test "$enable_selinux" = yes; then
+     { echo "$as_me:$LINENO: checking for getpeercon in -lselinux" >&5
+ echo $ECHO_N "checking for getpeercon in -lselinux... $ECHO_C" >&6; }
+ if test "${ac_cv_lib_selinux_getpeercon+set}" = set; then
+   echo $ECHO_N "(cached) $ECHO_C" >&6
+ else
+   ac_check_lib_save_LIBS=$LIBS
+ LIBS="-lselinux  $LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+ _ACEOF
+ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h.  */
+
+ /* Override any GCC internal prototype to avoid an error.
+    Use char because int might match the return type of a GCC
+    builtin and then its argument prototype would still apply.  */
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+ char getpeercon ();
+ int
+ main ()
+ {
+ return getpeercon ();
+   ;
+   return 0;
+ }
+ _ACEOF
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { (ac_try="$ac_link"
+ case "(($ac_try" in
+   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+   *) ac_try_echo=$ac_try;;
+ esac
+ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+   (eval "$ac_link") 2>conftest.er1
+   ac_status=$?
+   grep -v '^ *+' conftest.er1 >conftest.err
+   rm -f conftest.er1
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } && {
+      test -z "$ac_c_werror_flag" ||
+      test ! -s conftest.err
+        } && test -s conftest$ac_exeext &&
+        $as_test_x conftest$ac_exeext; then
+   ac_cv_lib_selinux_getpeercon=yes
+ else
+   echo "$as_me: failed program was:" >&5
+ sed 's/^/| /' conftest.$ac_ext >&5
+
+     ac_cv_lib_selinux_getpeercon=no
+ fi
+
+ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+       conftest$ac_exeext conftest.$ac_ext
+ LIBS=$ac_check_lib_save_LIBS
+ fi
+ { echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_getpeercon" >&5
+ echo "${ECHO_T}$ac_cv_lib_selinux_getpeercon" >&6; }
+ if test $ac_cv_lib_selinux_getpeercon = yes; then
+
+ cat >>confdefs.h <<_ACEOF
+ #define HAVE_SELINUX 1
+ _ACEOF
+
+
+ else
+   { { echo "$as_me:$LINENO: error: \"--enable-selinux requires libselinux.\"" >&5
+ echo "$as_me: error: \"--enable-selinux requires libselinux.\"" >&2;}
+    { (exit 1); exit 1; }; }
+ fi
+
+ fi
+
+ #
  # Elf
  #

*************** with_libxml!$with_libxml$ac_delim
*** 27803,27813 ****
  with_libxslt!$with_libxslt$ac_delim
  with_system_tzdata!$with_system_tzdata$ac_delim
  with_zlib!$with_zlib$ac_delim
  GREP!$GREP$ac_delim
  EGREP!$EGREP$ac_delim
  ELF_SYS!$ELF_SYS$ac_delim
  LDFLAGS_SL!$LDFLAGS_SL$ac_delim
- LD!$LD$ac_delim
  _ACEOF

    if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
--- 27911,27921 ----
  with_libxslt!$with_libxslt$ac_delim
  with_system_tzdata!$with_system_tzdata$ac_delim
  with_zlib!$with_zlib$ac_delim
+ enable_selinux!$enable_selinux$ac_delim
  GREP!$GREP$ac_delim
  EGREP!$EGREP$ac_delim
  ELF_SYS!$ELF_SYS$ac_delim
  LDFLAGS_SL!$LDFLAGS_SL$ac_delim
  _ACEOF

    if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
*************** _ACEOF
*** 27849,27854 ****
--- 27957,27963 ----
  ac_delim='%!_!# '
  for ac_last_try in false false false false false :; do
    cat >conf$$subs.sed <<_ACEOF
+ LD!$LD$ac_delim
  with_gnu_ld!$with_gnu_ld$ac_delim
  ld_R_works!$ld_R_works$ac_delim
  RANLIB!$RANLIB$ac_delim
*************** vpath_build!$vpath_build$ac_delim
*** 27911,27917 ****
  LTLIBOBJS!$LTLIBOBJS$ac_delim
  _ACEOF

!   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 60; then
      break
    elif $ac_last_try; then
      { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
--- 28020,28026 ----
  LTLIBOBJS!$LTLIBOBJS$ac_delim
  _ACEOF

!   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 61; then
      break
    elif $ac_last_try; then
      { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff -Nrpc base/configure.in sepgsql/configure.in
*** base/configure.in    Fri Jan 23 10:23:37 2009
--- sepgsql/configure.in    Fri Jan 23 10:55:35 2009
*************** PGAC_ARG_BOOL(with, zlib, yes,
*** 763,768 ****
--- 763,781 ----
  AC_SUBST(with_zlib)

  #
+ # SELinux support
+ #
+ PGAC_ARG_BOOL(enable, selinux, no,
+               [enable to build with SELinux support])
+ if test "$enable_selinux" = yes; then
+     AC_CHECK_LIB(selinux, getpeercon,
+                  AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1,
+                                     [SE-PostgreSQL feature is enabled])
+                  AC_SUBST(enable_selinux),
+                  AC_MSG_ERROR("--enable-selinux requires libselinux."))
+ fi
+
+ #
  # Elf
  #

diff -Nrpc base/src/Makefile.global.in sepgsql/src/Makefile.global.in
*** base/src/Makefile.global.in    Fri Jan 23 10:23:37 2009
--- sepgsql/src/Makefile.global.in    Fri Jan 23 10:55:35 2009
*************** enable_rpath    = @enable_rpath@
*** 164,169 ****
--- 164,170 ----
  enable_nls    = @enable_nls@
  enable_debug    = @enable_debug@
  enable_dtrace    = @enable_dtrace@
+ enable_selinux    = @enable_selinux@
  enable_coverage    = @enable_coverage@
  enable_thread_safety    = @enable_thread_safety@

diff -Nrpc base/src/backend/Makefile sepgsql/src/backend/Makefile
*** base/src/backend/Makefile    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/Makefile    Sat Jan  3 15:58:18 2009
*************** include $(top_builddir)/src/Makefile.glo
*** 16,22 ****

  SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
      main nodes optimizer port postmaster regex rewrite \
!     storage tcop tsearch utils $(top_builddir)/src/timezone

  include $(srcdir)/common.mk

--- 16,22 ----

  SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
      main nodes optimizer port postmaster regex rewrite \
!     security storage tcop tsearch utils $(top_builddir)/src/timezone

  include $(srcdir)/common.mk

*************** LIBS := $(filter-out -lpgport, $(LIBS))
*** 34,39 ****
--- 34,44 ----
  # The backend doesn't need everything that's in LIBS, however
  LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS))

+ # SELinux support needs to link libselinux
+ ifeq ($(enable_selinux), yes)
+ LIBS += -lselinux
+ endif
+
  ##########################################################################

  all: submake-libpgport postgres $(POSTGRES_IMP)
diff -Nrpc base/src/backend/access/common/heaptuple.c sepgsql/src/backend/access/common/heaptuple.c
*** base/src/backend/access/common/heaptuple.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/access/common/heaptuple.c    Sat Jan  3 15:58:18 2009
***************
*** 61,66 ****
--- 61,67 ----
  #include "access/sysattr.h"
  #include "access/tuptoaster.h"
  #include "executor/tuptable.h"
+ #include "security/pgace.h"


  /* Does att's datatype allow packing into the 1-byte-header varlena format? */
*************** heap_attisnull(HeapTuple tup, int attnum
*** 287,292 ****
--- 288,295 ----
          case MinCommandIdAttributeNumber:
          case MaxTransactionIdAttributeNumber:
          case MaxCommandIdAttributeNumber:
+         case SecurityAclAttributeNumber:
+         case SecurityLabelAttributeNumber:
              /* these are never null */
              break;

*************** heap_getsysattr(HeapTuple tup, int attnu
*** 599,604 ****
--- 602,613 ----
          case TableOidAttributeNumber:
              result = ObjectIdGetDatum(tup->t_tableOid);
              break;
+         case SecurityAclAttributeNumber:
+             result = rowaclHeapGetSecurityAclSysattr(tup);
+             break;
+         case SecurityLabelAttributeNumber:
+             result = pgaceHeapGetSecurityLabelSysattr(tup);
+             break;
          default:
              elog(ERROR, "invalid attnum: %d", attnum);
              result = 0;            /* keep compiler quiet */
*************** heap_form_tuple(TupleDesc tupleDescripto
*** 723,728 ****
--- 732,743 ----
      if (tupleDescriptor->tdhasoid)
          len += sizeof(Oid);

+     if (tupleDescriptor->tdhasrowacl)
+         len += sizeof(Oid);
+
+     if (tupleDescriptor->tdhasseclabel)
+         len += sizeof(Oid);
+
      hoff = len = MAXALIGN(len); /* align user data safely */

      data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
*************** heap_form_tuple(TupleDesc tupleDescripto
*** 754,759 ****
--- 769,779 ----
      if (tupleDescriptor->tdhasoid)        /* else leave infomask = 0 */
          td->t_infomask = HEAP_HASOID;

+     if (tupleDescriptor->tdhasrowacl)
+         td->t_infomask2 |= HEAP_HAS_ROWACL;
+     if (tupleDescriptor->tdhasseclabel)
+         td->t_infomask2 |= HEAP_HAS_SECLABEL;
+
      heap_fill_tuple(tupleDescriptor,
                      values,
                      isnull,
*************** heap_modify_tuple(HeapTuple tuple,
*** 864,869 ****
--- 884,893 ----
      newTuple->t_tableOid = tuple->t_tableOid;
      if (tupleDesc->tdhasoid)
          HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
+     if (HeapTupleHasRowAcl(newTuple))
+         HeapTupleSetRowAcl(newTuple, HeapTupleGetRowAcl(tuple));
+     if (HeapTupleHasSecLabel(newTuple))
+         HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple));

      return newTuple;
  }
*************** heap_form_minimal_tuple(TupleDesc tupleD
*** 1475,1480 ****
--- 1499,1510 ----
      if (tupleDescriptor->tdhasoid)
          len += sizeof(Oid);

+     if (tupleDescriptor->tdhasrowacl)
+         len += sizeof(Oid);
+
+     if (tupleDescriptor->tdhasseclabel)
+         len += sizeof(Oid);
+
      hoff = len = MAXALIGN(len); /* align user data safely */

      data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
*************** heap_form_minimal_tuple(TupleDesc tupleD
*** 1496,1501 ****
--- 1526,1536 ----
      if (tupleDescriptor->tdhasoid)        /* else leave infomask = 0 */
          tuple->t_infomask = HEAP_HASOID;

+     if (tupleDescriptor->tdhasrowacl)
+         tuple->t_infomask2 |= HEAP_HAS_ROWACL;
+     if (tupleDescriptor->tdhasseclabel)
+         tuple->t_infomask2 |= HEAP_HAS_SECLABEL;
+
      heap_fill_tuple(tupleDescriptor,
                      values,
                      isnull,
diff -Nrpc base/src/backend/access/common/reloptions.c sepgsql/src/backend/access/common/reloptions.c
*** base/src/backend/access/common/reloptions.c    Tue Jan 13 09:22:28 2009
--- sepgsql/src/backend/access/common/reloptions.c    Tue Jan 13 10:00:14 2009
***************
*** 22,27 ****
--- 22,28 ----
  #include "catalog/pg_type.h"
  #include "commands/defrem.h"
  #include "nodes/makefuncs.h"
+ #include "security/pgace.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
***************
*** 48,53 ****
--- 49,62 ----

  static relopt_bool boolRelOpts[] =
  {
+     {
+         {
+             "row_level_acl",
+             "Row-level ACLs validator",
+             RELOPT_KIND_HEAP
+         },
+         false,
+     },
      /* list terminator */
      { { NULL } }
  };
*************** static relopt_real realRelOpts[] =
*** 98,103 ****
--- 107,121 ----

  static relopt_string stringRelOpts[] =
  {
+     {
+         {
+             "default_row_acl",
+             "Default Row-level ACLs",
+             RELOPT_KIND_HEAP
+         },
+         0, true, rawaclValidateDefaultRowAclRelopt,
+         "",
+     },
      /* list terminator */
      { { NULL } }
  };
*************** default_reloptions(Datum reloptions, boo
*** 877,883 ****
      StdRdOptions   *rdopts;
      int                numoptions;
      relopt_parse_elt tab[] = {
!         {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}
      };

      options = parseRelOptions(reloptions, validate, kind, &numoptions);
--- 895,903 ----
      StdRdOptions   *rdopts;
      int                numoptions;
      relopt_parse_elt tab[] = {
!         {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
!         {"row_level_acl", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, row_level_acl)},
!         {"default_row_acl", RELOPT_TYPE_STRING, offsetof(StdRdOptions, default_row_acl)},
      };

      options = parseRelOptions(reloptions, validate, kind, &numoptions);
diff -Nrpc base/src/backend/access/common/tupdesc.c sepgsql/src/backend/access/common/tupdesc.c
*** base/src/backend/access/common/tupdesc.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/access/common/tupdesc.c    Fri Jan 23 10:55:35 2009
*************** CreateTemplateTupleDesc(int natts, bool
*** 88,93 ****
--- 88,95 ----
      desc->tdtypeid = RECORDOID;
      desc->tdtypmod = -1;
      desc->tdhasoid = hasoid;
+     desc->tdhasrowacl = false;        /* set a proper bool, if necessary */
+     desc->tdhasseclabel = false;    /* set a proper bool, if necessary */
      desc->tdrefcount = -1;        /* assume not reference-counted */

      return desc;
*************** CreateTupleDesc(int natts, bool hasoid,
*** 121,126 ****
--- 123,130 ----
      desc->tdtypeid = RECORDOID;
      desc->tdtypmod = -1;
      desc->tdhasoid = hasoid;
+     desc->tdhasrowacl = false;        /* set a proper bool, if necessary */
+     desc->tdhasseclabel = false;    /* set a proper bool, if necessary */
      desc->tdrefcount = -1;        /* assume not reference-counted */

      return desc;
*************** CreateTupleDescCopy(TupleDesc tupdesc)
*** 150,155 ****
--- 154,161 ----

      desc->tdtypeid = tupdesc->tdtypeid;
      desc->tdtypmod = tupdesc->tdtypmod;
+     desc->tdhasrowacl = tupdesc->tdhasrowacl;
+     desc->tdhasseclabel = tupdesc->tdhasseclabel;

      return desc;
  }
*************** CreateTupleDescCopyConstr(TupleDesc tupd
*** 208,213 ****
--- 214,221 ----

      desc->tdtypeid = tupdesc->tdtypeid;
      desc->tdtypmod = tupdesc->tdtypmod;
+     desc->tdhasrowacl = tupdesc->tdhasrowacl;
+     desc->tdhasseclabel = tupdesc->tdhasseclabel;

      return desc;
  }
*************** equalTupleDescs(TupleDesc tupdesc1, Tupl
*** 314,319 ****
--- 322,331 ----
          return false;
      if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
          return false;
+     if (tupdesc1->tdhasrowacl != tupdesc2->tdhasrowacl)
+         return false;
+     if (tupdesc1->tdhasseclabel != tupdesc2->tdhasseclabel)
+         return false;

      for (i = 0; i < tupdesc1->natts; i++)
      {
diff -Nrpc base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/heap/heapam.c
*** base/src/backend/access/heap/heapam.c    Thu Jan 22 14:34:54 2009
--- sepgsql/src/backend/access/heap/heapam.c    Thu Jan 22 14:41:23 2009
***************
*** 54,59 ****
--- 54,60 ----
  #include "catalog/namespace.h"
  #include "miscadmin.h"
  #include "pgstat.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/freespace.h"
  #include "storage/lmgr.h"
*************** heap_insert(Relation relation, HeapTuple
*** 2056,2061 ****
--- 2057,2068 ----
  Oid
  simple_heap_insert(Relation relation, HeapTuple tup)
  {
+     if (!pgaceHeapTupleInsert(relation, tup, true, false))
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("could not insert tuple on \"%s\" due to pgace security",
+                         RelationGetRelationName(relation))));
+
      return heap_insert(relation, tup, GetCurrentCommandId(true), 0, NULL);
  }

*************** simple_heap_delete(Relation relation, It
*** 2349,2354 ****
--- 2356,2367 ----
      ItemPointerData update_ctid;
      TransactionId update_xmax;

+     if (!pgaceHeapTupleDelete(relation, tid, true, false))
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("could not delete tuple on \"%s\" due to pgace security",
+                         RelationGetRelationName(relation))));
+
      result = heap_delete(relation, tid,
                           &update_ctid, &update_xmax,
                           GetCurrentCommandId(true), InvalidSnapshot,
*************** simple_heap_update(Relation relation, It
*** 3018,3023 ****
--- 3031,3042 ----
      ItemPointerData update_ctid;
      TransactionId update_xmax;

+     if (!pgaceHeapTupleUpdate(relation, otid, tup, true, false))
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("could not update tuple on \"%s\" due to pgace security",
+                         RelationGetRelationName(relation))));
+
      result = heap_update(relation, otid, tup,
                           &update_ctid, &update_xmax,
                           GetCurrentCommandId(true), InvalidSnapshot,
diff -Nrpc base/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access/heap/tuptoaster.c
*** base/src/backend/access/heap/tuptoaster.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/access/heap/tuptoaster.c    Wed Jan 14 09:52:01 2009
***************
*** 35,40 ****
--- 35,41 ----
  #include "access/tuptoaster.h"
  #include "access/xact.h"
  #include "catalog/catalog.h"
+ #include "security/pgace.h"
  #include "utils/fmgroids.h"
  #include "utils/pg_lzcompress.h"
  #include "utils/rel.h"
*************** toast_insert_or_update(Relation rel, Hea
*** 591,596 ****
--- 592,601 ----
          hoff += BITMAPLEN(numAttrs);
      if (newtup->t_data->t_infomask & HEAP_HASOID)
          hoff += sizeof(Oid);
+     if (HeapTupleHasRowAcl(newtup))
+         hoff += sizeof(Oid);
+     if (HeapTupleHasSecLabel(newtup))
+         hoff += sizeof(Oid);
      hoff = MAXALIGN(hoff);
      Assert(hoff == newtup->t_data->t_hoff);
      /* now convert to a limit on the tuple data size */
*************** toast_insert_or_update(Relation rel, Hea
*** 864,869 ****
--- 869,878 ----
              new_len += BITMAPLEN(numAttrs);
          if (olddata->t_infomask & HEAP_HASOID)
              new_len += sizeof(Oid);
+         if (HeapTupleHeaderHasRowAcl(olddata))
+             new_len += sizeof(Oid);
+         if (HeapTupleHeaderHasSecLabel(olddata))
+             new_len += sizeof(Oid);
          new_len = MAXALIGN(new_len);
          Assert(new_len == olddata->t_hoff);
          new_data_len = heap_compute_data_size(tupleDesc,
*************** toast_flatten_tuple_attribute(Datum valu
*** 1015,1020 ****
--- 1024,1033 ----
          new_len += BITMAPLEN(numAttrs);
      if (olddata->t_infomask & HEAP_HASOID)
          new_len += sizeof(Oid);
+     if (HeapTupleHeaderHasRowAcl(olddata))
+         new_len += sizeof(Oid);
+     if (HeapTupleHeaderHasSecLabel(olddata))
+         new_len += sizeof(Oid);
      new_len = MAXALIGN(new_len);
      Assert(new_len == olddata->t_hoff);
      new_data_len = heap_compute_data_size(tupleDesc,
*************** toast_save_datum(Relation rel, Datum val
*** 1213,1218 ****
--- 1226,1237 ----
          memcpy(VARDATA(&chunk_data), data_p, chunk_size);
          toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);

+         if (!pgaceHeapTupleInsert(toastrel, toasttup, true, false))
+             ereport(ERROR,
+                     (errcode(ERRCODE_PGACE_ERROR),
+                      errmsg("could not insert tuple \"%s\" due to pgace security",
+                             RelationGetRelationName(toastrel))));
+
          heap_insert(toastrel, toasttup, mycid, options, NULL);

          /*
diff -Nrpc base/src/backend/bootstrap/bootparse.y sepgsql/src/backend/bootstrap/bootparse.y
*** base/src/backend/bootstrap/bootparse.y    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/bootstrap/bootparse.y    Sat Jan  3 15:58:18 2009
***************
*** 42,47 ****
--- 42,48 ----
  #include "nodes/pg_list.h"
  #include "nodes/primnodes.h"
  #include "rewrite/prs2lock.h"
+ #include "security/pgace.h"
  #include "storage/block.h"
  #include "storage/fd.h"
  #include "storage/ipc.h"
*************** Boot_CreateStmt:
*** 206,211 ****
--- 207,221 ----
                                                     RELKIND_RELATION,
                                                     $3,
                                                     true);
+                         /*
+                          * fixup boot_reldesc->rd_att->tdhassec(acl|label) via PGACE
+                          */
+                         boot_reldesc->rd_rel->relkind = RELKIND_RELATION;
+                         boot_reldesc->rd_att->tdhasrowacl
+                             = pgaceTupleDescHasRowAcl(boot_reldesc, NIL);
+                         boot_reldesc->rd_att->tdhasseclabel
+                             = pgaceTupleDescHasSecLabel(boot_reldesc, NIL);
+
                          elog(DEBUG4, "bootstrap relation created");
                      }
                      else
*************** Boot_CreateStmt:
*** 225,231 ****
                                                        0,
                                                        ONCOMMIT_NOOP,
                                                        (Datum) 0,
!                                                       true);
                          elog(DEBUG4, "relation created with oid %u", id);
                      }
                      do_end();
--- 235,242 ----
                                                        0,
                                                        ONCOMMIT_NOOP,
                                                        (Datum) 0,
!                                                       true,
!                                                       NIL);
                          elog(DEBUG4, "relation created with oid %u", id);
                      }
                      do_end();
diff -Nrpc base/src/backend/bootstrap/bootstrap.c sepgsql/src/backend/bootstrap/bootstrap.c
*** base/src/backend/bootstrap/bootstrap.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/bootstrap/bootstrap.c    Fri Jan 23 10:55:35 2009
***************
*** 32,37 ****
--- 32,38 ----
  #include "nodes/makefuncs.h"
  #include "postmaster/bgwriter.h"
  #include "postmaster/walwriter.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/ipc.h"
  #include "storage/proc.h"
*************** BootstrapModeMain(void)
*** 500,505 ****
--- 501,508 ----
       */
      boot_yyparse();

+     pgacePostBootstrapingMode();
+
      /* Perform a checkpoint to ensure everything's down to disk */
      SetProcessingMode(NormalProcessing);
      CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
*************** InsertOneTuple(Oid objectid)
*** 797,802 ****
--- 800,810 ----
      tupDesc = CreateTupleDesc(numattr,
                                RelationGetForm(boot_reldesc)->relhasoids,
                                attrtypes);
+     tupDesc->tdhasrowacl
+         = rowaclTupleDescHasRowAcl(boot_reldesc, NIL);
+     tupDesc->tdhasseclabel
+         = pgaceTupleDescHasSecLabel(boot_reldesc, NIL);
+
      tuple = heap_form_tuple(tupDesc, values, Nulls);
      if (objectid != (Oid) 0)
          HeapTupleSetOid(tuple, objectid);
diff -Nrpc base/src/backend/catalog/Makefile sepgsql/src/backend/catalog/Makefile
*** base/src/backend/catalog/Makefile    Wed Dec 24 11:45:25 2008
--- sepgsql/src/backend/catalog/Makefile    Wed Dec 24 12:18:39 2008
*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr
*** 34,39 ****
--- 34,40 ----
      pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
      pg_database.h pg_tablespace.h pg_pltemplate.h \
      pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
+     pg_security.h \
      pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
      pg_ts_parser.h pg_ts_template.h \
      pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
diff -Nrpc base/src/backend/catalog/aclchk.c sepgsql/src/backend/catalog/aclchk.c
*** base/src/backend/catalog/aclchk.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/catalog/aclchk.c    Fri Jan 23 10:55:35 2009
*************** dumpacl(Acl *acl)
*** 105,111 ****
   *
   * NB: the original old_acl is pfree'd.
   */
! static Acl *
  merge_acl_with_grant(Acl *old_acl, bool is_grant,
                       bool grant_option, DropBehavior behavior,
                       List *grantees, AclMode privileges,
--- 105,111 ----
   *
   * NB: the original old_acl is pfree'd.
   */
! Acl *
  merge_acl_with_grant(Acl *old_acl, bool is_grant,
                       bool grant_option, DropBehavior behavior,
                       List *grantees, AclMode privileges,
diff -Nrpc base/src/backend/catalog/catalog.c sepgsql/src/backend/catalog/catalog.c
*** base/src/backend/catalog/catalog.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/catalog/catalog.c    Sat Jan  3 15:58:18 2009
***************
*** 31,36 ****
--- 31,37 ----
  #include "catalog/pg_database.h"
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_pltemplate.h"
+ #include "catalog/pg_security.h"
  #include "catalog/pg_shdepend.h"
  #include "catalog/pg_shdescription.h"
  #include "catalog/pg_tablespace.h"
*************** IsSharedRelation(Oid relationId)
*** 304,309 ****
--- 305,311 ----
          relationId == AuthMemRelationId ||
          relationId == DatabaseRelationId ||
          relationId == PLTemplateRelationId ||
+         relationId == SecurityRelationId ||
          relationId == SharedDescriptionRelationId ||
          relationId == SharedDependRelationId ||
          relationId == TableSpaceRelationId)
*************** IsSharedRelation(Oid relationId)
*** 316,321 ****
--- 318,325 ----
          relationId == DatabaseNameIndexId ||
          relationId == DatabaseOidIndexId ||
          relationId == PLTemplateNameIndexId ||
+         relationId == SecurityOidIndexId ||
+         relationId == SecuritySeclabelIndexId ||
          relationId == SharedDescriptionObjIndexId ||
          relationId == SharedDependDependerIndexId ||
          relationId == SharedDependReferenceIndexId ||
diff -Nrpc base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c
*** base/src/backend/catalog/heap.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/catalog/heap.c    Fri Jan 23 10:55:35 2009
***************
*** 56,61 ****
--- 56,62 ----
  #include "parser/parse_coerce.h"
  #include "parser/parse_expr.h"
  #include "parser/parse_relation.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/freespace.h"
  #include "storage/smgr.h"
*************** static void AddNewRelationTuple(Relation
*** 74,80 ****
                      Oid new_rel_oid, Oid new_type_oid,
                      Oid relowner,
                      char relkind,
!                     Datum reloptions);
  static Oid AddNewRelationType(const char *typeName,
                     Oid typeNamespace,
                     Oid new_rel_oid,
--- 75,82 ----
                      Oid new_rel_oid, Oid new_type_oid,
                      Oid relowner,
                      char relkind,
!                     Datum reloptions,
!                     List *pgaceAttrList);
  static Oid AddNewRelationType(const char *typeName,
                     Oid typeNamespace,
                     Oid new_rel_oid,
*************** static List *insert_ordered_unique_oid(L
*** 112,148 ****
  static FormData_pg_attribute a1 = {
      0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
      SelfItemPointerAttributeNumber, 0, -1, -1,
!     false, 'p', 's', true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a2 = {
      0, {"oid"}, OIDOID, 0, sizeof(Oid),
      ObjectIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a3 = {
      0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
      MinTransactionIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a4 = {
      0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
      MinCommandIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a5 = {
      0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
      MaxTransactionIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a6 = {
      0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
      MaxCommandIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', true, false, false, true, 0, { 0 }
  };

  /*
--- 114,150 ----
  static FormData_pg_attribute a1 = {
      0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
      SelfItemPointerAttributeNumber, 0, -1, -1,
!     false, 'p', 's', 0, true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a2 = {
      0, {"oid"}, OIDOID, 0, sizeof(Oid),
      ObjectIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', 0, true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a3 = {
      0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
      MinTransactionIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', 0, true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a4 = {
      0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
      MinCommandIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', 0, true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a5 = {
      0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
      MaxTransactionIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', 0, true, false, false, true, 0, { 0 }
  };

  static FormData_pg_attribute a6 = {
      0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
      MaxCommandIdAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', 0, true, false, false, true, 0, { 0 }
  };

  /*
*************** static FormData_pg_attribute a6 = {
*** 154,163 ****
  static FormData_pg_attribute a7 = {
      0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
      TableOidAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', true, false, false, true, 0, { 0 }
  };

! static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};

  /*
   * This function returns a Form_pg_attribute pointer for a system attribute.
--- 156,177 ----
  static FormData_pg_attribute a7 = {
      0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
      TableOidAttributeNumber, 0, -1, -1,
!     true, 'p', 'i', 0, true, false, false, true, 0, { 0 }
  };

! static FormData_pg_attribute a8 = {
!     0, {SecurityAclAttributeName}, ACLITEMARRAYOID, 0, -1,
!     SecurityAclAttributeNumber, 1, -1, -1,
!     false, 'x', 'i', 0, true, false, false, true, 0, { 0 }
! };
!
! static FormData_pg_attribute a9 = {
!     0, {SecurityLabelAttributeName}, TEXTOID, 0, -1,
!     SecurityLabelAttributeNumber, 0, -1, -1,
!     false, 'x', 'i', 0, true, false, false, true, 0, { 0 }
! };
!
! static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9};

  /*
   * This function returns a Form_pg_attribute pointer for a system attribute.
*************** SystemAttributeByName(const char *attnam
*** 197,202 ****
--- 211,229 ----
      return NULL;
  }

+ /*
+  * This function returns true, if the given attribute number is writable
+  * system column. If not, returns false.
+  */
+ bool
+ SystemAttributeIsWritable(AttrNumber attnum)
+ {
+     if (attnum == SecurityAclAttributeNumber ||
+         attnum == SecurityLabelAttributeNumber)
+         return true;
+
+     return false;
+ }

  /* ----------------------------------------------------------------
   *                XXX END OF UGLY HARD CODED BADNESS XXX
*************** CheckAttributeType(const char *attname,
*** 486,492 ****
  void
  InsertPgAttributeTuple(Relation pg_attribute_rel,
                         Form_pg_attribute new_attribute,
!                        CatalogIndexState indstate)
  {
      Datum        values[Natts_pg_attribute];
      bool        nulls[Natts_pg_attribute];
--- 513,520 ----
  void
  InsertPgAttributeTuple(Relation pg_attribute_rel,
                         Form_pg_attribute new_attribute,
!                        CatalogIndexState indstate,
!                        List *pgaceAttrList)
  {
      Datum        values[Natts_pg_attribute];
      bool        nulls[Natts_pg_attribute];
*************** InsertPgAttributeTuple(Relation pg_attri
*** 508,513 ****
--- 536,542 ----
      values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(new_attribute->attbyval);
      values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(new_attribute->attstorage);
      values[Anum_pg_attribute_attalign - 1] = CharGetDatum(new_attribute->attalign);
+     values[Anum_pg_attribute_attkind - 1] = CharGetDatum(new_attribute->attkind);
      values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(new_attribute->attnotnull);
      values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(new_attribute->atthasdef);
      values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
*************** InsertPgAttributeTuple(Relation pg_attri
*** 519,524 ****
--- 548,555 ----

      tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);

+     pgaceCreateAttributeCommon(pg_attribute_rel, tup, pgaceAttrList);
+
      /* finally insert the new tuple, update the indexes, and clean up */
      simple_heap_insert(pg_attribute_rel, tup);

*************** AddNewAttributeTuples(Oid new_rel_oid,
*** 541,547 ****
                        TupleDesc tupdesc,
                        char relkind,
                        bool oidislocal,
!                       int oidinhcount)
  {
      Form_pg_attribute attr;
      int            i;
--- 572,579 ----
                        TupleDesc tupdesc,
                        char relkind,
                        bool oidislocal,
!                       int oidinhcount,
!                       List *pgaceAttrList)
  {
      Form_pg_attribute attr;
      int            i;
*************** AddNewAttributeTuples(Oid new_rel_oid,
*** 565,577 ****
      for (i = 0; i < natts; i++)
      {
          attr = tupdesc->attrs[i];
!         /* Fill in the correct relation OID */
          attr->attrelid = new_rel_oid;
          /* Make sure these are OK, too */
          attr->attstattarget = -1;
          attr->attcacheoff = -1;

!         InsertPgAttributeTuple(rel, attr, indstate);

          /* Add dependency info */
          myself.classId = RelationRelationId;
--- 597,610 ----
      for (i = 0; i < natts; i++)
      {
          attr = tupdesc->attrs[i];
!         /* Fill in the correct relation OID and relkind */
          attr->attrelid = new_rel_oid;
+         attr->attkind = relkind;
          /* Make sure these are OK, too */
          attr->attstattarget = -1;
          attr->attcacheoff = -1;

!         InsertPgAttributeTuple(rel, attr, indstate, pgaceAttrList);

          /* Add dependency info */
          myself.classId = RelationRelationId;
*************** AddNewAttributeTuples(Oid new_rel_oid,
*** 603,608 ****
--- 636,642 ----

              /* Fill in the correct relation OID in the copied tuple */
              attStruct.attrelid = new_rel_oid;
+             attStruct.attkind = relkind;

              /* Fill in correct inheritance info for the OID column */
              if (attStruct.attnum == ObjectIdAttributeNumber)
*************** AddNewAttributeTuples(Oid new_rel_oid,
*** 611,617 ****
                  attStruct.attinhcount = oidinhcount;
              }

!             InsertPgAttributeTuple(rel, &attStruct, indstate);
          }
      }

--- 645,651 ----
                  attStruct.attinhcount = oidinhcount;
              }

!             InsertPgAttributeTuple(rel, &attStruct, indstate, pgaceAttrList);
          }
      }

*************** void
*** 639,645 ****
  InsertPgClassTuple(Relation pg_class_desc,
                     Relation new_rel_desc,
                     Oid new_rel_oid,
!                    Datum reloptions)
  {
      Form_pg_class rd_rel = new_rel_desc->rd_rel;
      Datum        values[Natts_pg_class];
--- 673,680 ----
  InsertPgClassTuple(Relation pg_class_desc,
                     Relation new_rel_desc,
                     Oid new_rel_oid,
!                    Datum reloptions,
!                    List *pgaceAttrList)
  {
      Form_pg_class rd_rel = new_rel_desc->rd_rel;
      Datum        values[Natts_pg_class];
*************** InsertPgClassTuple(Relation pg_class_des
*** 686,697 ****
--- 721,736 ----
       * be embarrassing to do this sort of thing in polite company.
       */
      HeapTupleSetOid(tup, new_rel_oid);
+     pgaceCreateRelationCommon(pg_class_desc, tup, pgaceAttrList);

      /* finally insert the new tuple, update the indexes, and clean up */
      simple_heap_insert(pg_class_desc, tup);

      CatalogUpdateIndexes(pg_class_desc, tup);

+     /* temporary use for this tuple */
+     InsertSysCache(RelationGetRelid(pg_class_desc), tup);
+
      heap_freetuple(tup);
  }

*************** AddNewRelationTuple(Relation pg_class_de
*** 709,715 ****
                      Oid new_type_oid,
                      Oid relowner,
                      char relkind,
!                     Datum reloptions)
  {
      Form_pg_class new_rel_reltup;

--- 748,755 ----
                      Oid new_type_oid,
                      Oid relowner,
                      char relkind,
!                     Datum reloptions,
!                     List *pgaceAttrList)
  {
      Form_pg_class new_rel_reltup;

*************** AddNewRelationTuple(Relation pg_class_de
*** 769,775 ****
      new_rel_desc->rd_att->tdtypeid = new_type_oid;

      /* Now build and insert the tuple */
!     InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
  }


--- 809,816 ----
      new_rel_desc->rd_att->tdtypeid = new_type_oid;

      /* Now build and insert the tuple */
!     InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
!                        reloptions, pgaceAttrList);
  }


*************** heap_create_with_catalog(const char *rel
*** 838,844 ****
                           int oidinhcount,
                           OnCommitAction oncommit,
                           Datum reloptions,
!                          bool allow_system_table_mods)
  {
      Relation    pg_class_desc;
      Relation    new_rel_desc;
--- 879,886 ----
                           int oidinhcount,
                           OnCommitAction oncommit,
                           Datum reloptions,
!                          bool allow_system_table_mods,
!                          List *pgaceAttrList)
  {
      Relation    pg_class_desc;
      Relation    new_rel_desc;
*************** heap_create_with_catalog(const char *rel
*** 1012,1024 ****
                          new_type_oid,
                          ownerid,
                          relkind,
!                         reloptions);

      /*
       * now add tuples to pg_attribute for the attributes in our new relation.
       */
      AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
!                           oidislocal, oidinhcount);

      /*
       * Make a dependency link to force the relation to be deleted if its
--- 1054,1075 ----
                          new_type_oid,
                          ownerid,
                          relkind,
!                         reloptions,
!                         pgaceAttrList);

      /*
       * now add tuples to pg_attribute for the attributes in our new relation.
       */
      AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
!                           oidislocal, oidinhcount, pgaceAttrList);
!
!     /*
!      * Fixup rel->rd_att->tdhassecacl and rel->rd_att->tdhasseclabel
!      */
!     new_rel_desc->rd_att->tdhasrowacl
!         = pgaceTupleDescHasRowAcl(new_rel_desc, NIL);
!     new_rel_desc->rd_att->tdhasseclabel
!         = pgaceTupleDescHasSecLabel(new_rel_desc, NIL);

      /*
       * Make a dependency link to force the relation to be deleted if its
diff -Nrpc base/src/backend/catalog/index.c sepgsql/src/backend/catalog/index.c
*** base/src/backend/catalog/index.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/catalog/index.c    Fri Jan 23 10:55:35 2009
***************
*** 48,53 ****
--- 48,54 ----
  #include "nodes/nodeFuncs.h"
  #include "optimizer/clauses.h"
  #include "optimizer/var.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/lmgr.h"
  #include "storage/procarray.h"
*************** InitializeAttributeOids(Relation indexRe
*** 315,321 ****
--- 316,325 ----
      tupleDescriptor = RelationGetDescr(indexRelation);

      for (i = 0; i < numatts; i += 1)
+     {
          tupleDescriptor->attrs[i]->attrelid = indexoid;
+         tupleDescriptor->attrs[i]->attkind = RELKIND_INDEX;
+     }
  }

  /* ----------------------------------------------------------------
*************** AppendAttributeTuples(Relation indexRela
*** 351,357 ****
          Assert(indexTupDesc->attrs[i]->attnum == i + 1);
          Assert(indexTupDesc->attrs[i]->attcacheoff == -1);

!         InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], indstate);
      }

      CatalogCloseIndexes(indstate);
--- 355,361 ----
          Assert(indexTupDesc->attrs[i]->attnum == i + 1);
          Assert(indexTupDesc->attrs[i]->attcacheoff == -1);

!         InsertPgAttributeTuple(pg_attribute, indexTupDesc->attrs[i], indstate, NIL);
      }

      CatalogCloseIndexes(indstate);
*************** index_create(Oid heapRelationId,
*** 630,635 ****
--- 634,647 ----
      Assert(indexRelationId == RelationGetRelid(indexRelation));

      /*
+      * Fixup rel->rd_att->tdhassecXXX
+      */
+     indexRelation->rd_att->tdhasrowacl
+         = pgaceTupleDescHasRowAcl(indexRelation, NIL);
+     indexRelation->rd_att->tdhasseclabel
+         = pgaceTupleDescHasSecLabel(indexRelation, NIL);
+
+     /*
       * Obtain exclusive lock on it.  Although no other backends can see it
       * until we commit, this prevents deadlock-risk complaints from lock
       * manager in cases such as CLUSTER.
*************** index_create(Oid heapRelationId,
*** 652,658 ****
       */
      InsertPgClassTuple(pg_class, indexRelation,
                         RelationGetRelid(indexRelation),
!                        reloptions);

      /* done with pg_class */
      heap_close(pg_class, RowExclusiveLock);
--- 664,670 ----
       */
      InsertPgClassTuple(pg_class, indexRelation,
                         RelationGetRelid(indexRelation),
!                        reloptions, NIL);

      /* done with pg_class */
      heap_close(pg_class, RowExclusiveLock);
diff -Nrpc base/src/backend/catalog/pg_aggregate.c sepgsql/src/backend/catalog/pg_aggregate.c
*** base/src/backend/catalog/pg_aggregate.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/catalog/pg_aggregate.c    Sat Jan  3 15:58:18 2009
*************** AggregateCreate(const char *aggName,
*** 231,237 ****
                                NIL,                        /* parameterDefaults */
                                PointerGetDatum(NULL),    /* proconfig */
                                1,    /* procost */
!                               0);        /* prorows */

      /*
       * Okay to create the pg_aggregate entry.
--- 231,238 ----
                                NIL,                        /* parameterDefaults */
                                PointerGetDatum(NULL),    /* proconfig */
                                1,    /* procost */
!                               0,        /* prorows */
!                               NULL);    /* PGACE opaque */

      /*
       * Okay to create the pg_aggregate entry.
diff -Nrpc base/src/backend/catalog/pg_largeobject.c sepgsql/src/backend/catalog/pg_largeobject.c
*** base/src/backend/catalog/pg_largeobject.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/catalog/pg_largeobject.c    Sat Jan  3 15:58:18 2009
***************
*** 18,23 ****
--- 18,24 ----
  #include "access/heapam.h"
  #include "catalog/indexing.h"
  #include "catalog/pg_largeobject.h"
+ #include "security/pgace.h"
  #include "utils/builtins.h"
  #include "utils/fmgroids.h"
  #include "utils/rel.h"
*************** LargeObjectCreate(Oid loid)
*** 59,64 ****
--- 60,67 ----

      ntup = heap_form_tuple(pg_largeobject->rd_att, values, nulls);

+     pgaceLargeObjectCreate(pg_largeobject, ntup);
+
      /*
       * Insert it
       */
*************** LargeObjectDrop(Oid loid)
*** 80,85 ****
--- 83,89 ----
      ScanKeyData skey[1];
      SysScanDesc sd;
      HeapTuple    tuple;
+     void       *pgaceItem = NULL;

      ScanKeyInit(&skey[0],
                  Anum_pg_largeobject_loid,
*************** LargeObjectDrop(Oid loid)
*** 93,98 ****
--- 97,103 ----

      while ((tuple = systable_getnext(sd)) != NULL)
      {
+         pgaceLargeObjectDrop(pg_largeobject, tuple, &pgaceItem);
          simple_heap_delete(pg_largeobject, &tuple->t_self);
          found = true;
      }
diff -Nrpc base/src/backend/catalog/pg_proc.c sepgsql/src/backend/catalog/pg_proc.c
*** base/src/backend/catalog/pg_proc.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/catalog/pg_proc.c    Fri Jan 23 10:55:35 2009
***************
*** 29,34 ****
--- 29,35 ----
  #include "miscadmin.h"
  #include "nodes/nodeFuncs.h"
  #include "parser/parse_type.h"
+ #include "security/pgace.h"
  #include "tcop/pquery.h"
  #include "tcop/tcopprot.h"
  #include "utils/acl.h"
*************** ProcedureCreate(const char *procedureNam
*** 78,84 ****
                  List *parameterDefaults,
                  Datum proconfig,
                  float4 procost,
!                 float4 prorows)
  {
      Oid            retval;
      int            parameterCount;
--- 79,86 ----
                  List *parameterDefaults,
                  Datum proconfig,
                  float4 procost,
!                 float4 prorows,
!                 void *pgaceItem)
  {
      Oid            retval;
      int            parameterCount;
*************** ProcedureCreate(const char *procedureNam
*** 474,479 ****
--- 476,482 ----

          /* Okay, do it... */
          tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
+         pgaceGramCreateFunction(rel, tup, (DefElem *)pgaceItem);
          simple_heap_update(rel, &tup->t_self, tup);

          ReleaseSysCache(oldtup);
*************** ProcedureCreate(const char *procedureNam
*** 483,488 ****
--- 486,492 ----
      {
          /* Creating a new procedure */
          tup = heap_form_tuple(tupDesc, values, nulls);
+         pgaceGramCreateFunction(rel, tup, (DefElem *)pgaceItem);
          simple_heap_insert(rel, tup);
          is_update = false;
      }
diff -Nrpc base/src/backend/catalog/toasting.c sepgsql/src/backend/catalog/toasting.c
*** base/src/backend/catalog/toasting.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/catalog/toasting.c    Sat Jan  3 15:58:18 2009
*************** create_toast_table(Relation rel, Oid toa
*** 200,206 ****
                                             0,
                                             ONCOMMIT_NOOP,
                                             (Datum) 0,
!                                            true);

      /* make the toast relation visible, else index creation will fail */
      CommandCounterIncrement();
--- 200,207 ----
                                             0,
                                             ONCOMMIT_NOOP,
                                             (Datum) 0,
!                                            true,
!                                            NIL);

      /* make the toast relation visible, else index creation will fail */
      CommandCounterIncrement();
diff -Nrpc base/src/backend/commands/cluster.c sepgsql/src/backend/commands/cluster.c
*** base/src/backend/commands/cluster.c    Thu Jan 22 14:34:54 2009
--- sepgsql/src/backend/commands/cluster.c    Thu Jan 22 14:41:23 2009
*************** make_new_heap(Oid OIDOldHeap, const char
*** 711,717 ****
                                            0,
                                            ONCOMMIT_NOOP,
                                            reloptions,
!                                           allowSystemTableMods);

      ReleaseSysCache(tuple);

--- 711,718 ----
                                            0,
                                            ONCOMMIT_NOOP,
                                            reloptions,
!                                           allowSystemTableMods,
!                                           NIL);

      ReleaseSysCache(tuple);

*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 906,911 ****
--- 907,920 ----
          if (NewHeap->rd_rel->relhasoids)
              HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));

+         /* Preserve RowACL, if any */
+         if (HeapTupleHasRowAcl(copiedTuple))
+             HeapTupleSetRowAcl(copiedTuple, HeapTupleGetRowAcl(tuple));
+
+         /* Preserve SecLabel, if any */
+         if (HeapTupleHasSecLabel(copiedTuple))
+             HeapTupleSetSecLabel(copiedTuple, HeapTupleGetSecLabel(tuple));
+
          /* The heap rewrite module does the rest */
          rewrite_heap_tuple(rwstate, tuple, copiedTuple);

diff -Nrpc base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c
*** base/src/backend/commands/copy.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/commands/copy.c    Wed Jan 14 15:02:53 2009
***************
*** 21,27 ****
--- 21,29 ----
  #include <arpa/inet.h>

  #include "access/heapam.h"
+ #include "access/sysattr.h"
  #include "access/xact.h"
+ #include "catalog/heap.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/copy.h"
***************
*** 34,39 ****
--- 36,42 ----
  #include "optimizer/planner.h"
  #include "parser/parse_relation.h"
  #include "rewrite/rewriteHandler.h"
+ #include "security/pgace.h"
  #include "storage/fd.h"
  #include "tcop/tcopprot.h"
  #include "utils/acl.h"
*************** typedef struct CopyStateData
*** 160,165 ****
--- 163,176 ----
      char       *raw_buf;
      int            raw_buf_index;    /* next byte to process */
      int            raw_buf_len;    /* total # of bytes stored */
+
+     /* dump/restore support for security_acl */
+     FmgrInfo    rowacl_out_function;
+     bool        rowacl_force_quot;
+
+     /* dump/restore support for security_label */
+     FmgrInfo    seclabel_out_function;
+     bool        seclabel_force_quot;
  } CopyStateData;

  typedef CopyStateData *CopyState;
*************** static const char BinarySignature[11] =
*** 243,249 ****
  /* non-export function prototypes */
  static void DoCopyTo(CopyState cstate);
  static void CopyTo(CopyState cstate);
! static void CopyOneRowTo(CopyState cstate, Oid tupleOid,
               Datum *values, bool *nulls);
  static void CopyFrom(CopyState cstate);
  static bool CopyReadLine(CopyState cstate);
--- 254,260 ----
  /* non-export function prototypes */
  static void DoCopyTo(CopyState cstate);
  static void CopyTo(CopyState cstate);
! static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid rowAclId, Oid secLabelId,
               Datum *values, bool *nulls);
  static void CopyFrom(CopyState cstate);
  static bool CopyReadLine(CopyState cstate);
*************** DoCopy(const CopyStmt *stmt, const char
*** 1072,1077 ****
--- 1083,1090 ----
      /* Generate or convert list of attributes to process */
      cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);

+     pgaceCopyTable(cstate->rel, cstate->attnumlist, is_from);
+
      num_phys_attrs = tupDesc->natts;

      /* Convert FORCE QUOTE name list to per-column flags, check validity */
*************** DoCopy(const CopyStmt *stmt, const char
*** 1088,1098 ****
              int            attnum = lfirst_int(cur);

              if (!list_member_int(cstate->attnumlist, attnum))
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                     errmsg("FORCE QUOTE column \"%s\" not referenced by COPY",
!                           NameStr(tupDesc->attrs[attnum - 1]->attname))));
!             cstate->force_quote_flags[attnum - 1] = true;
          }
      }

--- 1101,1136 ----
              int            attnum = lfirst_int(cur);

              if (!list_member_int(cstate->attnumlist, attnum))
+             {
+                 Form_pg_attribute attForm;
+
+                 if (SystemAttributeIsWritable(attnum))
+                     attForm = SystemAttributeDefinition(attnum, true);
+                 else
+                     attForm = tupDesc->attrs[attnum - 1];
+
+                 Assert(attForm != NULL);
+
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                     errmsg("FORCE QUOTE column \"%s\" not referenced by COPY",
!                           NameStr(attForm->attname))));
!             }
!
!             switch (attnum)
!             {
!             case SecurityAclAttributeNumber:
!                 cstate->rowacl_force_quot = true;
!                 break;
!
!             case SecurityLabelAttributeNumber:
!                 cstate->seclabel_force_quot = true;
!                 break;
!
!             default:
!                 cstate->force_quote_flags[attnum - 1] = true;
!                 break;
!             }
          }
      }

*************** DoCopy(const CopyStmt *stmt, const char
*** 1110,1119 ****
              int            attnum = lfirst_int(cur);

              if (!list_member_int(cstate->attnumlist, attnum))
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                  errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY",
!                        NameStr(tupDesc->attrs[attnum - 1]->attname))));
              cstate->force_notnull_flags[attnum - 1] = true;
          }
      }
--- 1148,1171 ----
              int            attnum = lfirst_int(cur);

              if (!list_member_int(cstate->attnumlist, attnum))
+             {
+                 Form_pg_attribute attForm;
+
+                 if (SystemAttributeIsWritable(attnum))
+                     attForm = SystemAttributeDefinition(attnum, true);
+                 else
+                     attForm = tupDesc->attrs[attnum - 1];
+
+                 Assert(attForm != NULL);
+
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                  errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY",
!                        NameStr(attForm->attname))));
!             }
!             if (SystemAttributeIsWritable(attnum))
!                 continue;    /* ignore, if specified */
!
              cstate->force_notnull_flags[attnum - 1] = true;
          }
      }
*************** DoCopyTo(CopyState cstate)
*** 1242,1247 ****
--- 1294,1302 ----
              ereport(ERROR,
                      (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                       errmsg("\"%s\" is a directory", cstate->filename)));
+
+         pgaceCopyFile(cstate->rel, fileno(cstate->copy_file),
+                       cstate->filename, false);
      }

      PG_TRY();
*************** CopyTo(CopyState cstate)
*** 1305,1320 ****
          int            attnum = lfirst_int(cur);
          Oid            out_func_oid;
          bool        isvarlena;

          if (cstate->binary)
!             getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid,
                                      &out_func_oid,
                                      &isvarlena);
          else
!             getTypeOutputInfo(attr[attnum - 1]->atttypid,
                                &out_func_oid,
                                &isvarlena);
!         fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]);
      }

      /*
--- 1360,1393 ----
          int            attnum = lfirst_int(cur);
          Oid            out_func_oid;
          bool        isvarlena;
+         FmgrInfo    *out_fmgr;
+         Form_pg_attribute attForm;
+
+         switch (attnum)
+         {
+         case SecurityAclAttributeNumber:
+             attForm = SystemAttributeDefinition(attnum, true);
+             out_fmgr = &cstate->rowacl_out_function;
+             break;
+         case SecurityLabelAttributeNumber:
+             attForm = SystemAttributeDefinition(attnum, true);
+             out_fmgr = &cstate->seclabel_out_function;
+             break;
+         default:    /* user columns */
+             attForm = attr[attnum - 1];
+             out_fmgr = &cstate->out_functions[attnum - 1];
+             break;
+         }

          if (cstate->binary)
!             getTypeBinaryOutputInfo(attForm->atttypid,
                                      &out_func_oid,
                                      &isvarlena);
          else
!             getTypeOutputInfo(attForm->atttypid,
                                &out_func_oid,
                                &isvarlena);
!         fmgr_info(out_func_oid, out_fmgr);
      }

      /*
*************** CopyTo(CopyState cstate)
*** 1369,1375 ****
                      CopySendChar(cstate, cstate->delim[0]);
                  hdr_delim = true;

!                 colname = NameStr(attr[attnum - 1]->attname);

                  CopyAttributeOutCSV(cstate, colname, false,
                                      list_length(cstate->attnumlist) == 1);
--- 1442,1455 ----
                      CopySendChar(cstate, cstate->delim[0]);
                  hdr_delim = true;

!                 if (SystemAttributeIsWritable(attnum))
!                 {
!                     Form_pg_attribute attForm
!                         = SystemAttributeDefinition(attnum, true);
!                     colname = NameStr(attForm->attname);
!                 }
!                 else
!                     colname = NameStr(attr[attnum - 1]->attname);

                  CopyAttributeOutCSV(cstate, colname, false,
                                      list_length(cstate->attnumlist) == 1);
*************** CopyTo(CopyState cstate)
*** 1395,1405 ****
          {
              CHECK_FOR_INTERRUPTS();

              /* Deconstruct the tuple ... faster than repeated heap_getattr */
              heap_deform_tuple(tuple, tupDesc, values, nulls);

              /* Format and send the data */
!             CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls);
          }

          heap_endscan(scandesc);
--- 1475,1492 ----
          {
              CHECK_FOR_INTERRUPTS();

+             if (!pgaceCopyToTuple(cstate->rel, cstate->attnumlist, tuple))
+                 continue;
+
              /* Deconstruct the tuple ... faster than repeated heap_getattr */
              heap_deform_tuple(tuple, tupDesc, values, nulls);

              /* Format and send the data */
!             CopyOneRowTo(cstate,
!                          HeapTupleGetOid(tuple),
!                          HeapTupleGetRowAcl(tuple),
!                          HeapTupleGetSecLabel(tuple),
!                          values, nulls);
          }

          heap_endscan(scandesc);
*************** CopyTo(CopyState cstate)
*** 1425,1431 ****
   * Emit one row during CopyTo().
   */
  static void
! CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
  {
      bool        need_delim = false;
      FmgrInfo   *out_functions = cstate->out_functions;
--- 1512,1519 ----
   * Emit one row during CopyTo().
   */
  static void
! CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid rowAclId, Oid secLabelId,
!              Datum *values, bool *nulls)
  {
      bool        need_delim = false;
      FmgrInfo   *out_functions = cstate->out_functions;
*************** CopyOneRowTo(CopyState cstate, Oid tuple
*** 1464,1471 ****
      foreach(cur, cstate->attnumlist)
      {
          int            attnum = lfirst_int(cur);
!         Datum        value = values[attnum - 1];
!         bool        isnull = nulls[attnum - 1];

          if (!cstate->binary)
          {
--- 1552,1561 ----
      foreach(cur, cstate->attnumlist)
      {
          int            attnum = lfirst_int(cur);
!         Datum        value;
!         bool        isnull;
!         bool        force_quot;
!         FmgrInfo    *out_fmgr;

          if (!cstate->binary)
          {
*************** CopyOneRowTo(CopyState cstate, Oid tuple
*** 1474,1479 ****
--- 1564,1594 ----
              need_delim = true;
          }

+         switch (attnum)
+         {
+         case SecurityAclAttributeNumber:
+             value = PointerGetDatum(rowaclSidToSecurityAcl(rowAclId,
+                                             RelationGetForm(cstate->rel)->relowner));
+             isnull = false;
+             force_quot = cstate->rowacl_force_quot;
+             out_fmgr = &cstate->rowacl_out_function;
+             break;
+
+         case SecurityLabelAttributeNumber:
+             value = CStringGetTextDatum(pgaceSidToSecurityLabel(secLabelId));
+             isnull = false;
+             force_quot = cstate->seclabel_force_quot;
+             out_fmgr = &cstate->seclabel_out_function;
+             break;
+
+         default:
+             value = values[attnum - 1];
+             isnull = nulls[attnum - 1];
+             force_quot = cstate->force_quote_flags[attnum - 1];
+             out_fmgr = &out_functions[attnum - 1];
+             break;
+         }
+
          if (isnull)
          {
              if (!cstate->binary)
*************** CopyOneRowTo(CopyState cstate, Oid tuple
*** 1485,1495 ****
          {
              if (!cstate->binary)
              {
!                 string = OutputFunctionCall(&out_functions[attnum - 1],
!                                             value);
                  if (cstate->csv_mode)
!                     CopyAttributeOutCSV(cstate, string,
!                                         cstate->force_quote_flags[attnum - 1],
                                          list_length(cstate->attnumlist) == 1);
                  else
                      CopyAttributeOutText(cstate, string);
--- 1600,1608 ----
          {
              if (!cstate->binary)
              {
!                 string = OutputFunctionCall(out_fmgr, value);
                  if (cstate->csv_mode)
!                     CopyAttributeOutCSV(cstate, string, force_quot,
                                          list_length(cstate->attnumlist) == 1);
                  else
                      CopyAttributeOutText(cstate, string);
*************** CopyOneRowTo(CopyState cstate, Oid tuple
*** 1498,1505 ****
              {
                  bytea       *outputbytes;

!                 outputbytes = SendFunctionCall(&out_functions[attnum - 1],
!                                                value);
                  CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
                  CopySendData(cstate, VARDATA(outputbytes),
                               VARSIZE(outputbytes) - VARHDRSZ);
--- 1611,1617 ----
              {
                  bytea       *outputbytes;

!                 outputbytes = SendFunctionCall(out_fmgr, value);
                  CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
                  CopySendData(cstate, VARDATA(outputbytes),
                               VARSIZE(outputbytes) - VARHDRSZ);
*************** CopyFrom(CopyState cstate)
*** 1633,1642 ****
--- 1745,1759 ----
                  num_defaults;
      FmgrInfo   *in_functions;
      FmgrInfo    oid_in_function;
+     FmgrInfo    rowacl_in_function;
+     FmgrInfo    seclabel_in_function;
      Oid           *typioparams;
      Oid            oid_typioparam;
+     Oid            rowacl_typioparam;
+     Oid            seclabel_typioparam;
      int            attnum;
      int            i;
+     ListCell   *l;
      Oid            in_func_oid;
      Datum       *values;
      bool       *nulls;
*************** CopyFrom(CopyState cstate)
*** 1737,1742 ****
--- 1854,1862 ----
              ereport(ERROR,
                      (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                       errmsg("\"%s\" is a directory", cstate->filename)));
+
+         pgaceCopyFile(cstate->rel, fileno(cstate->copy_file),
+                       cstate->filename, true);
      }

      tupDesc = RelationGetDescr(cstate->rel);
*************** CopyFrom(CopyState cstate)
*** 1872,1877 ****
--- 1992,2027 ----
          fmgr_info(in_func_oid, &oid_in_function);
      }

+     foreach (l, cstate->attnumlist)
+     {
+         switch (lfirst_int(l))
+         {
+         case SecurityAclAttributeNumber:
+             if (!cstate->binary)
+                 getTypeInputInfo(ACLITEMARRAYOID,
+                                  &in_func_oid,
+                                  &rowacl_typioparam);
+             else
+                 getTypeBinaryInputInfo(ACLITEMARRAYOID,
+                                        &in_func_oid,
+                                        &rowacl_typioparam);
+             fmgr_info(in_func_oid, &rowacl_in_function);
+             break;
+
+         case SecurityLabelAttributeNumber:
+             if (!cstate->binary)
+                 getTypeInputInfo(TEXTOID,
+                                  &in_func_oid,
+                                  &seclabel_typioparam);
+             else
+                 getTypeBinaryInputInfo(TEXTOID,
+                                        &in_func_oid,
+                                        &seclabel_typioparam);
+             fmgr_info(in_func_oid, &seclabel_in_function);
+             break;
+         }
+     }
+
      values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
      nulls = (bool *) palloc(num_phys_attrs * sizeof(bool));

*************** CopyFrom(CopyState cstate)
*** 1906,1911 ****
--- 2056,2063 ----
      {
          bool        skip_tuple;
          Oid            loaded_oid = InvalidOid;
+         Datum        loaded_rowacl = PointerGetDatum(NULL);
+         Datum        loaded_seclabel = PointerGetDatum(NULL);

          CHECK_FOR_INTERRUPTS();

*************** CopyFrom(CopyState cstate)
*** 1980,1985 ****
--- 2132,2176 ----
                  int            attnum = lfirst_int(cur);
                  int            m = attnum - 1;

+                 if (SystemAttributeIsWritable(attnum))
+                 {
+                     Form_pg_attribute attForm
+                         = SystemAttributeDefinition(attnum, true);
+
+                     if (fieldno >= fldct)
+                         ereport(ERROR,
+                                 (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+                                  errmsg("missing data for column \"%s\"",
+                                         NameStr(attForm->attname))));
+                     string = field_strings[fieldno++];
+                     cstate->cur_attname = NameStr(attForm->attname);
+                     cstate->cur_attval = string;
+                     if (string)
+                     {
+                         switch (attnum)
+                         {
+                         case SecurityAclAttributeNumber:
+                             loaded_rowacl
+                                 = InputFunctionCall(&rowacl_in_function,
+                                                     string,
+                                                     rowacl_typioparam,
+                                                     attForm->atttypmod);
+                             break;
+
+                         case SecurityLabelAttributeNumber:
+                             loaded_seclabel
+                                 = InputFunctionCall(&seclabel_in_function,
+                                                     string,
+                                                     seclabel_typioparam,
+                                                     attForm->atttypmod);
+                             break;
+                         }
+                     }
+                     cstate->cur_attname = NULL;
+                     cstate->cur_attval = NULL;
+                     continue;
+                 }
+
                  if (fieldno >= fldct)
                      ereport(ERROR,
                              (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
*************** CopyFrom(CopyState cstate)
*** 2050,2055 ****
--- 2241,2281 ----
                  int            attnum = lfirst_int(cur);
                  int            m = attnum - 1;

+                 if (SystemAttributeIsWritable(attnum))
+                 {
+                     Form_pg_attribute attForm
+                         = SystemAttributeDefinition(attnum, false);
+                     Datum tmp;
+
+                     cstate->cur_attname = NameStr(attForm->attname);
+                     i++;
+
+                     switch (attnum)
+                     {
+                     case SecurityAclAttributeNumber:
+                         tmp = CopyReadBinaryAttribute(cstate, i,
+                                                       &rowacl_in_function,
+                                                       rowacl_typioparam,
+                                                       attForm->atttypmod,
+                                                       &isnull);
+                         if (!isnull)
+                             loaded_seclabel = tmp;
+                         break;
+
+                     case SecurityLabelAttributeNumber:
+                         tmp = CopyReadBinaryAttribute(cstate, i,
+                                                       &seclabel_in_function,
+                                                       seclabel_typioparam,
+                                                       attForm->atttypmod,
+                                                       &isnull);
+                         if (!isnull)
+                             loaded_seclabel = tmp;
+                         break;
+                     }
+                     cstate->cur_attname = NULL;
+                     continue;
+                 }
+
                  cstate->cur_attname = NameStr(attr[m]->attname);
                  i++;
                  values[m] = CopyReadBinaryAttribute(cstate,
*************** CopyFrom(CopyState cstate)
*** 2079,2084 ****
--- 2305,2322 ----
          if (cstate->oids && file_has_oids)
              HeapTupleSetOid(tuple, loaded_oid);

+         if (loaded_rowacl != PointerGetDatum(NULL))
+         {
+             Acl *acl = DatumGetAclP(loaded_rowacl);
+             HeapTupleSetRowAcl(tuple, rowaclSecurityAclToSid(acl));
+         }
+
+         if (loaded_seclabel != PointerGetDatum(NULL))
+         {
+             char *label = TextDatumGetCString(loaded_seclabel);
+             HeapTupleSetSecLabel(tuple, pgaceSecurityLabelToSid(label));
+         }
+
          /* Triggers and stuff need to be invoked in query context. */
          MemoryContextSwitchTo(oldcontext);

*************** CopyFrom(CopyState cstate)
*** 2101,2106 ****
--- 2339,2349 ----
              }
          }

+         if (!skip_tuple && !rowaclHeapTupleInsert(cstate->rel, tuple, false, false))
+             skip_tuple = true;
+         if (!skip_tuple && !pgaceHeapTupleInsert(cstate->rel, tuple, false, false))
+             skip_tuple = true;
+
          if (!skip_tuple)
          {
              /* Place tuple in tuple slot */
*************** CopyGetAttnums(TupleDesc tupDesc, Relati
*** 3379,3384 ****
--- 3622,3637 ----
                      break;
                  }
              }
+
+             /* Is it writable system column? */
+             if (attnum == InvalidAttrNumber)
+             {
+                 Form_pg_attribute attForm
+                     = SystemAttributeByName(name, tupDesc->tdhasoid);
+                 if (attForm && SystemAttributeIsWritable(attForm->attnum))
+                     attnum = attForm->attnum;
+             }
+
              if (attnum == InvalidAttrNumber)
              {
                  if (rel != NULL)
*************** copy_dest_receive(TupleTableSlot *slot,
*** 3428,3434 ****
      slot_getallattrs(slot);

      /* And send the data */
!     CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull);
  }

  /*
--- 3681,3689 ----
      slot_getallattrs(slot);

      /* And send the data */
!     CopyOneRowTo(cstate,
!                  InvalidOid, InvalidOid, InvalidOid,
!                  slot->tts_values, slot->tts_isnull);
  }

  /*
diff -Nrpc base/src/backend/commands/dbcommands.c sepgsql/src/backend/commands/dbcommands.c
*** base/src/backend/commands/dbcommands.c    Thu Jan 22 14:34:54 2009
--- sepgsql/src/backend/commands/dbcommands.c    Thu Jan 22 14:41:23 2009
***************
*** 41,46 ****
--- 41,47 ----
  #include "miscadmin.h"
  #include "pgstat.h"
  #include "postmaster/bgwriter.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/fd.h"
  #include "storage/lmgr.h"
*************** createdb(const CreatedbStmt *stmt)
*** 119,124 ****
--- 120,126 ----
      DefElem    *dcollate = NULL;
      DefElem    *dctype = NULL;
      DefElem    *dconnlimit = NULL;
+     DefElem       *dpgace_item = NULL;
      char       *dbname = stmt->dbname;
      char       *dbowner = NULL;
      const char *dbtemplate = NULL;
*************** createdb(const CreatedbStmt *stmt)
*** 200,205 ****
--- 202,214 ----
                       errmsg("LOCATION is not supported anymore"),
                       errhint("Consider using tablespaces instead.")));
          }
+         else if (pgaceIsGramSecurityItem(defel)) {
+             if (dpgace_item)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             dpgace_item = defel;
+         }
          else
              elog(ERROR, "option \"%s\" not recognized",
                   defel->defname);
*************** createdb(const CreatedbStmt *stmt)
*** 532,537 ****
--- 541,547 ----
                             new_record, new_record_nulls);

      HeapTupleSetOid(tuple, dboid);
+     pgaceGramCreateDatabase(pg_database_rel, tuple, dpgace_item);

      simple_heap_insert(pg_database_rel, tuple);

*************** AlterDatabase(AlterDatabaseStmt *stmt, b
*** 1278,1283 ****
--- 1288,1294 ----
      int            connlimit = -1;
      DefElem    *dconnlimit = NULL;
      DefElem    *dtablespace = NULL;
+     DefElem       *dpgace_item = NULL;
      Datum        new_record[Natts_pg_database];
      bool        new_record_nulls[Natts_pg_database];
      bool        new_record_repl[Natts_pg_database];
*************** AlterDatabase(AlterDatabaseStmt *stmt, b
*** 1303,1308 ****
--- 1314,1327 ----
                           errmsg("conflicting or redundant options")));
              dtablespace = defel;
          }
+         else if (pgaceIsGramSecurityItem(defel))
+         {
+             if (dpgace_item)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             dpgace_item = defel;
+         }
          else
              elog(ERROR, "option \"%s\" not recognized",
                   defel->defname);
*************** AlterDatabase(AlterDatabaseStmt *stmt, b
*** 1358,1363 ****
--- 1377,1383 ----

      newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), new_record,
                                  new_record_nulls, new_record_repl);
+     pgaceGramAlterDatabase(rel, newtuple, dpgace_item);
      simple_heap_update(rel, &tuple->t_self, newtuple);

      /* Update indexes */
diff -Nrpc base/src/backend/commands/functioncmds.c sepgsql/src/backend/commands/functioncmds.c
*** base/src/backend/commands/functioncmds.c    Tue Jan  6 14:45:31 2009
--- sepgsql/src/backend/commands/functioncmds.c    Tue Jan  6 14:52:44 2009
***************
*** 53,58 ****
--- 53,59 ----
  #include "parser/parse_expr.h"
  #include "parser/parse_func.h"
  #include "parser/parse_type.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/fmgroids.h"
*************** compute_attributes_sql_style(List *optio
*** 517,523 ****
                               bool *security_definer,
                               ArrayType **proconfig,
                               float4 *procost,
!                              float4 *prorows)
  {
      ListCell   *option;
      DefElem    *as_item = NULL;
--- 518,525 ----
                               bool *security_definer,
                               ArrayType **proconfig,
                               float4 *procost,
!                              float4 *prorows,
!                              DefElem **pgaceItem)
  {
      ListCell   *option;
      DefElem    *as_item = NULL;
*************** compute_attributes_sql_style(List *optio
*** 558,563 ****
--- 560,573 ----
                           errmsg("conflicting or redundant options")));
              windowfunc_item = defel;
          }
+         else if (pgaceIsGramSecurityItem(defel))
+         {
+             if (*pgaceItem)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             *pgaceItem = defel;
+         }
          else if (compute_common_attribute(defel,
                                            &volatility_item,
                                            &strict_item,
*************** CreateFunction(CreateFunctionStmt *stmt,
*** 765,770 ****
--- 775,781 ----
      HeapTuple    languageTuple;
      Form_pg_language languageStruct;
      List       *as_clause;
+     DefElem    *pgaceItem = NULL;

      /* Convert list of names to a name and namespace */
      namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
*************** CreateFunction(CreateFunctionStmt *stmt,
*** 790,796 ****
                                   &as_clause, &language,
                                   &isWindowFunc, &volatility,
                                   &isStrict, &security,
!                                  &proconfig, &procost, &prorows);

      /* Convert language name to canonical case */
      languageName = case_translate_language_name(language);
--- 801,807 ----
                                   &as_clause, &language,
                                   &isWindowFunc, &volatility,
                                   &isStrict, &security,
!                                  &proconfig, &procost, &prorows, &pgaceItem);

      /* Convert language name to canonical case */
      languageName = case_translate_language_name(language);
*************** CreateFunction(CreateFunctionStmt *stmt,
*** 926,932 ****
                      parameterDefaults,
                      PointerGetDatum(proconfig),
                      procost,
!                     prorows);
  }


--- 937,944 ----
                      parameterDefaults,
                      PointerGetDatum(proconfig),
                      procost,
!                     prorows,
!                     pgaceItem);
  }


*************** AlterFunction(AlterFunctionStmt *stmt)
*** 1276,1281 ****
--- 1288,1294 ----
      List       *set_items = NIL;
      DefElem    *cost_item = NULL;
      DefElem    *rows_item = NULL;
+     DefElem       *pgaceItem = NULL;

      rel = heap_open(ProcedureRelationId, RowExclusiveLock);

*************** AlterFunction(AlterFunctionStmt *stmt)
*** 1307,1312 ****
--- 1320,1334 ----
      {
          DefElem    *defel = (DefElem *) lfirst(l);

+         if (pgaceIsGramSecurityItem(defel)) {
+             if (pgaceItem)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             pgaceItem = defel;
+             continue;
+         }
+
          if (compute_common_attribute(defel,
                                       &volatility_item,
                                       &strict_item,
*************** AlterFunction(AlterFunctionStmt *stmt)
*** 1377,1382 ****
--- 1399,1405 ----
          tup = heap_modify_tuple(tup, RelationGetDescr(rel),
                                 repl_val, repl_null, repl_repl);
      }
+     pgaceGramAlterFunction(rel, tup, pgaceItem);

      /* Do the update */
      simple_heap_update(rel, &tup->t_self, tup);
diff -Nrpc base/src/backend/commands/lockcmds.c sepgsql/src/backend/commands/lockcmds.c
*** base/src/backend/commands/lockcmds.c    Tue Jan 13 09:22:28 2009
--- sepgsql/src/backend/commands/lockcmds.c    Tue Jan 13 09:39:35 2009
***************
*** 20,25 ****
--- 20,26 ----
  #include "miscadmin.h"
  #include "optimizer/prep.h"
  #include "parser/parse_clause.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/lsyscache.h"
  #include "utils/rel.h"
*************** LockTableCommand(LockStmt *lockstmt)
*** 71,76 ****
--- 72,79 ----
                  aclcheck_error(aclresult, ACL_KIND_CLASS,
                                 get_rel_name(childreloid));

+             pgaceLockTable(childreloid);
+
              if (lockstmt->nowait)
                  rel = relation_open_nowait(childreloid, lockstmt->mode);
              else
diff -Nrpc base/src/backend/commands/proclang.c sepgsql/src/backend/commands/proclang.c
*** base/src/backend/commands/proclang.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/commands/proclang.c    Sat Jan  3 15:58:18 2009
*************** CreateProceduralLanguage(CreatePLangStmt
*** 151,157 ****
                                           NIL,
                                           PointerGetDatum(NULL),
                                           1,
!                                          0);
          }

          /*
--- 151,158 ----
                                           NIL,
                                           PointerGetDatum(NULL),
                                           1,
!                                          0,
!                                          NULL);
          }

          /*
*************** CreateProceduralLanguage(CreatePLangStmt
*** 186,192 ****
                                           NIL,
                                           PointerGetDatum(NULL),
                                           1,
!                                          0);
              }
          }
          else
--- 187,194 ----
                                           NIL,
                                           PointerGetDatum(NULL),
                                           1,
!                                          0,
!                                          NULL);
              }
          }
          else
diff -Nrpc base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/tablecmds.c
*** base/src/backend/commands/tablecmds.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/commands/tablecmds.c    Fri Jan 23 10:55:35 2009
***************
*** 63,68 ****
--- 63,69 ----
  #include "parser/parser.h"
  #include "rewrite/rewriteDefine.h"
  #include "rewrite/rewriteHandler.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/lmgr.h"
  #include "storage/smgr.h"
*************** DefineRelation(CreateStmt *stmt, char re
*** 509,515 ****
                                            parentOidCount,
                                            stmt->oncommit,
                                            reloptions,
!                                           allowSystemTableMods);

      StoreCatalogInheritance(relationId, inheritOids);

--- 510,517 ----
                                            parentOidCount,
                                            stmt->oncommit,
                                            reloptions,
!                                           allowSystemTableMods,
!                                           pgaceRelationAttrList(stmt));

      StoreCatalogInheritance(relationId, inheritOids);

*************** ExecuteTruncate(TruncateStmt *stmt)
*** 856,861 ****
--- 858,865 ----
          heap_truncate_check_FKs(rels, false);
  #endif

+     pgaceExecTruncate(rels);
+
      /*
       * If we are asked to restart sequences, find all the sequences,
       * lock them (we only need AccessShareLock because that's all that
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2491,2496 ****
--- 2495,2501 ----
          case AT_DisableRule:
          case AT_AddInherit:        /* INHERIT / NO INHERIT */
          case AT_DropInherit:
+         case AT_SetSecurityLabel:
              ATSimplePermissions(rel, false);
              /* These commands never recurse */
              /* No command-specific prep needed */
*************** ATExecCmd(List **wqueue, AlteredTableInf
*** 2718,2723 ****
--- 2723,2731 ----
          case AT_DropInherit:
              ATExecDropInherit(rel, (RangeVar *) cmd->def);
              break;
+         case AT_SetSecurityLabel:
+             pgaceAlterRelationCommon(rel, cmd);
+             break;
          default:                /* oops */
              elog(ERROR, "unrecognized alter table type: %d",
                   (int) cmd->subtype);
*************** ATRewriteTable(AlteredTableInfo *tab, Oi
*** 3056,3066 ****
--- 3064,3080 ----
              if (newrel)
              {
                  Oid            tupOid = InvalidOid;
+                 Oid            tupRowAcl = InvalidOid;
+                 Oid            tupSecLabel = InvalidOid;

                  /* Extract data from old tuple */
                  heap_deform_tuple(tuple, oldTupDesc, values, isnull);
                  if (oldTupDesc->tdhasoid)
                      tupOid = HeapTupleGetOid(tuple);
+                 if (HeapTupleHasRowAcl(tuple))
+                     tupRowAcl = HeapTupleGetRowAcl(tuple);
+                 if (HeapTupleHasSecLabel(tuple))
+                     tupSecLabel = HeapTupleGetSecLabel(tuple);

                  /* Set dropped attributes to null in new tuple */
                  foreach(lc, dropped_attrs)
*************** ATRewriteTable(AlteredTableInfo *tab, Oi
*** 3092,3097 ****
--- 3106,3117 ----
                  /* Preserve OID, if any */
                  if (newTupDesc->tdhasoid)
                      HeapTupleSetOid(tuple, tupOid);
+                 /* Preserve RowAcl, if any */
+                 if (HeapTupleHasRowAcl(tuple))
+                     HeapTupleSetRowAcl(tuple, tupRowAcl);
+                 /* Preserve SecLabel, if any */
+                 if (HeapTupleHasSecLabel(tuple))
+                     HeapTupleSetSecLabel(tuple, tupSecLabel);
              }

              /* Now check any constraints on the possibly-changed tuple */
*************** ATExecAddColumn(AlteredTableInfo *tab, R
*** 3585,3590 ****
--- 3605,3611 ----
      attribute.attndims = list_length(colDef->typename->arrayBounds);
      attribute.attstorage = tform->typstorage;
      attribute.attalign = tform->typalign;
+     attribute.attkind = relkind;
      attribute.attnotnull = colDef->is_not_null;
      attribute.atthasdef = false;
      attribute.attisdropped = false;
*************** ATExecAddColumn(AlteredTableInfo *tab, R
*** 3594,3600 ****

      ReleaseSysCache(typeTuple);

!     InsertPgAttributeTuple(attrdesc, &attribute, NULL);

      heap_close(attrdesc, RowExclusiveLock);

--- 3615,3621 ----

      ReleaseSysCache(typeTuple);

!     InsertPgAttributeTuple(attrdesc, &attribute, NULL, NIL);

      heap_close(attrdesc, RowExclusiveLock);

diff -Nrpc base/src/backend/commands/trigger.c sepgsql/src/backend/commands/trigger.c
*** base/src/backend/commands/trigger.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/commands/trigger.c    Fri Jan 23 10:55:35 2009
***************
*** 33,38 ****
--- 33,39 ----
  #include "nodes/makefuncs.h"
  #include "parser/parse_func.h"
  #include "pgstat.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "tcop/utility.h"
  #include "utils/acl.h"
*************** ExecCallTriggerFunc(TriggerData *trigdat
*** 1560,1569 ****
--- 1561,1576 ----
       * call.
       */
      if (finfo->fn_oid == InvalidOid)
+     {
          fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
+         pgaceCallFunction(finfo);
+     }

      Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);

+     if (!pgaceCallTriggerFunction(trigdata))
+         return (HeapTuple) NULL;
+
      /*
       * If doing EXPLAIN ANALYZE, start charging time to this trigger.
       */
*************** ExecBRUpdateTriggers(EState *estate, Res
*** 1984,1989 ****
--- 1991,2014 ----
      if (newSlot != NULL)
          intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);

+     /*
+      * The before-row-triggers are fired prior to transcribing system
+      * attributes from the old tuple to the new one. When no explicit
+      * new values are given, we have to preserve them, so the following
+      * code do it to avoid to make triggers get confusion.
+      */
+     if (HeapTupleHasOid(newtuple) &&
+         !OidIsValid(HeapTupleGetOid(newtuple)))
+         HeapTupleSetOid(newtuple, HeapTupleGetOid(trigtuple));
+
+     if (HeapTupleHasRowAcl(newtuple) &&
+         !OidIsValid(HeapTupleGetRowAcl(newtuple)))
+         HeapTupleSetRowAcl(newtuple, HeapTupleGetRowAcl(trigtuple));
+
+     if (HeapTupleHasSecLabel(newtuple) &&
+         !OidIsValid(HeapTupleGetSecLabel(newtuple)))
+         HeapTupleSetSecLabel(newtuple, HeapTupleGetSecLabel(trigtuple));
+
      LocTriggerData.type = T_TriggerData;
      LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
          TRIGGER_EVENT_ROW |
diff -Nrpc base/src/backend/executor/execJunk.c sepgsql/src/backend/executor/execJunk.c
*** base/src/backend/executor/execJunk.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/execJunk.c    Sat Jan  3 15:58:18 2009
***************
*** 60,66 ****
   * An optional resultSlot can be passed as well.
   */
  JunkFilter *
! ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
  {
      JunkFilter *junkfilter;
      TupleDesc    cleanTupType;
--- 60,68 ----
   * An optional resultSlot can be passed as well.
   */
  JunkFilter *
! ExecInitJunkFilter(List *targetList,
!                    bool hasoid, bool hassecacl, bool hasseclabel,
!                    TupleTableSlot *slot)
  {
      JunkFilter *junkfilter;
      TupleDesc    cleanTupType;
*************** ExecInitJunkFilter(List *targetList, boo
*** 72,78 ****
      /*
       * Compute the tuple descriptor for the cleaned tuple.
       */
!     cleanTupType = ExecCleanTypeFromTL(targetList, hasoid);

      /*
       * Use the given slot, or make a new slot if we weren't given one.
--- 74,80 ----
      /*
       * Compute the tuple descriptor for the cleaned tuple.
       */
!     cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hassecacl, hasseclabel);

      /*
       * Use the given slot, or make a new slot if we weren't given one.
diff -Nrpc base/src/backend/executor/execMain.c sepgsql/src/backend/executor/execMain.c
*** base/src/backend/executor/execMain.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/executor/execMain.c    Fri Jan 23 10:55:35 2009
***************
*** 50,55 ****
--- 50,56 ----
  #include "optimizer/clauses.h"
  #include "parser/parse_clause.h"
  #include "parser/parsetree.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/lmgr.h"
  #include "storage/smgr.h"
*************** standard_ExecutorStart(QueryDesc *queryD
*** 158,163 ****
--- 159,166 ----
      Assert(queryDesc != NULL);
      Assert(queryDesc->estate == NULL);

+     pgaceExecutorStart(queryDesc, eflags);
+
      /*
       * If the transaction is read-only, we need to check if any writes are
       * planned to non-temporary tables.  EXPLAIN is considered read-only.
*************** InitPlan(QueryDesc *queryDesc, int eflag
*** 901,916 ****
                  for (i = 0; i < as_nplans; i++)
                  {
                      PlanState  *subplan = appendplans[i];
                      JunkFilter *j;

                      if (operation == CMD_UPDATE)
!                         ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
!                                             subplan->plan->targetlist);

                      j = ExecInitJunkFilter(subplan->plan->targetlist,
!                             resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
!                                   ExecAllocTableSlot(estate->es_tupleTable));
!
                      /*
                       * Since it must be UPDATE/DELETE, there had better be a
                       * "ctid" junk attribute in the tlist ... but ctid could
--- 904,920 ----
                  for (i = 0; i < as_nplans; i++)
                  {
                      PlanState  *subplan = appendplans[i];
+                     Relation    resultRel = resultRelInfo->ri_RelationDesc;
                      JunkFilter *j;

                      if (operation == CMD_UPDATE)
!                         ExecCheckPlanOutput(resultRel, subplan->plan->targetlist);

                      j = ExecInitJunkFilter(subplan->plan->targetlist,
!                                            RelationGetDescr(resultRel)->tdhasoid,
!                                            RelationGetDescr(resultRel)->tdhasrowacl,
!                                            RelationGetDescr(resultRel)->tdhasseclabel,
!                                            ExecAllocTableSlot(estate->es_tupleTable));
                      /*
                       * Since it must be UPDATE/DELETE, there had better be a
                       * "ctid" junk attribute in the tlist ... but ctid could
*************** InitPlan(QueryDesc *queryDesc, int eflag
*** 952,959 ****
                                          planstate->plan->targetlist);

                  j = ExecInitJunkFilter(planstate->plan->targetlist,
!                                        tupType->tdhasoid,
!                                   ExecAllocTableSlot(estate->es_tupleTable));
                  estate->es_junkFilter = j;
                  if (estate->es_result_relation_info)
                      estate->es_result_relation_info->ri_junkFilter = j;
--- 956,963 ----
                                          planstate->plan->targetlist);

                  j = ExecInitJunkFilter(planstate->plan->targetlist,
!                                        tupType->tdhasoid, tupType->tdhasrowacl, tupType->tdhasseclabel,
!                                        ExecAllocTableSlot(estate->es_tupleTable));
                  estate->es_junkFilter = j;
                  if (estate->es_result_relation_info)
                      estate->es_result_relation_info->ri_junkFilter = j;
*************** InitPlan(QueryDesc *queryDesc, int eflag
*** 1023,1029 ****
           * We assume all the sublists will generate the same output tupdesc.
           */
          tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
!                                  false);

          /* Set up a slot for the output of the RETURNING projection(s) */
          slot = ExecAllocTableSlot(estate->es_tupleTable);
--- 1027,1033 ----
           * We assume all the sublists will generate the same output tupdesc.
           */
          tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
!                                  false, false, false);

          /* Set up a slot for the output of the RETURNING projection(s) */
          slot = ExecAllocTableSlot(estate->es_tupleTable);
*************** ExecContextForcesOids(PlanState *plansta
*** 1346,1351 ****
--- 1350,1417 ----
      return false;
  }

+ /*
+  * ExecContextForcesRowAcl
+  *
+  * We need to ensure that result tuples have space for row level ACLs.
+  * If row_level_acl = true on the given relation, it should be allocated.
+  */
+ bool ExecContextForcesRowAcl(PlanState *planstate, bool *hasrowacl)
+ {
+     if (planstate->state->es_select_into)
+     {
+         IntoClause *into = planstate->state->es_plannedstmt->intoClause;
+
+         Assert(into != NULL);
+
+         *hasrowacl = pgaceTupleDescHasRowAcl(NULL, into->options);
+         return true;
+     }
+     else
+     {
+         ResultRelInfo *ri = planstate->state->es_result_relation_info;
+
+         if (ri && ri->ri_RelationDesc)
+         {
+             *hasrowacl = pgaceTupleDescHasRowAcl(ri->ri_RelationDesc, NIL);
+             return true;
+         }
+     }
+
+     return false;
+ }
+
+ /*
+  * ExecContextForcesSecLabel
+  *
+  * We need to ensure that result tuples have space for security label,
+  * if the security feature need to store it within the given relation.
+  */
+ bool ExecContextForcesSecLabel(PlanState *planstate, bool *hassecurity)
+ {
+     if (planstate->state->es_select_into)
+     {
+         IntoClause *into = planstate->state->es_plannedstmt->intoClause;
+
+         Assert(into != NULL);
+
+         *hassecurity = pgaceTupleDescHasSecLabel(NULL, into->options);
+         return true;
+     }
+     else
+     {
+         ResultRelInfo *ri = planstate->state->es_result_relation_info;
+
+         if (ri && ri->ri_RelationDesc)
+         {
+             *hassecurity = pgaceTupleDescHasSecLabel(ri->ri_RelationDesc, NIL);
+             return true;
+         }
+     }
+
+     return false;
+ }
+
  /* ----------------------------------------------------------------
   *        ExecEndPlan
   *
*************** ExecEndPlan(PlanState *planstate, EState
*** 1426,1431 ****
--- 1492,1581 ----
      }
  }

+ /*
+  * fetchWritableSystemAttribute() fetches writable system column data
+  * using Junkfilter, and saves them at TupleTableSlot temporary.
+  *
+  * storeWritableSystemAttribute() copies these fetched data into
+  * header structure of HeapTuple.
+  */
+ static void
+ fetchWritableSystemAttribute(JunkFilter *junkfilter, TupleTableSlot *slot,
+                              Datum *tts_rowacl, Datum *tts_seclabel)
+ {
+     AttrNumber attno;
+     Datum datum;
+     bool isnull;
+
+     /* for Row-level ACLs */
+     attno = ExecFindJunkAttribute(junkfilter, SecurityAclAttributeName);
+     if (attno != InvalidAttrNumber)
+     {
+         datum = ExecGetJunkAttribute(slot, attno, &isnull);
+         if (isnull)
+             ereport(ERROR,
+                     (errcode(ERRCODE_ROWACL_ERROR),
+                      errmsg("setting NULL on \"%s\" system column is not supported",
+                             SecurityAclAttributeName)));
+         *tts_rowacl = datum;
+     }
+
+     /* for Security Label */
+     attno = ExecFindJunkAttribute(junkfilter, SecurityLabelAttributeName);
+     if (attno != InvalidAttrNumber)
+     {
+         datum = ExecGetJunkAttribute(slot, attno, &isnull);
+         if (isnull)
+             ereport(ERROR,
+                     (errcode(ERRCODE_PGACE_ERROR),
+                      errmsg("setting NULL on \"%s\" system column is not supported",
+                             SecurityLabelAttributeName)));
+         *tts_seclabel = datum;
+     }
+ }
+
+ static void
+ storeWritableSystemAttribute(Relation rel, TupleTableSlot *slot, HeapTuple tuple)
+ {
+     /* for Row-level ACLs */
+     if (HeapTupleHasRowAcl(tuple))
+     {
+         if (!DatumGetPointer(slot->tts_rowacl))
+             HeapTupleSetRowAcl(tuple, InvalidOid);
+         else
+         {
+             Acl *acl = DatumGetAclP(slot->tts_rowacl);
+             HeapTupleSetRowAcl(tuple, rowaclSecurityAclToSid(acl));
+         }
+     }
+     else if (DatumGetPointer(slot->tts_rowacl))
+     {
+         ereport(ERROR,
+                 (errcode(ERRCODE_ROWACL_ERROR),
+                  errmsg("Row-level ACLs are unavailable for relation: %s",
+                         RelationGetRelationName(rel))));
+     }
+
+     /* for Security Label */
+     if (HeapTupleHasSecLabel(tuple))
+     {
+         if (!DatumGetPointer(slot->tts_seclabel))
+             HeapTupleSetSecLabel(tuple, InvalidOid);
+         else
+         {
+             char *label = TextDatumGetCString(slot->tts_seclabel);
+             HeapTupleSetSecLabel(tuple, pgaceSecurityLabelToSid(label));
+         }
+     }
+     else if (DatumGetPointer(slot->tts_seclabel))
+     {
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("Security Label is unavailable for relation: %s",
+                         RelationGetRelationName(rel))));
+     }
+ }
+
  /* ----------------------------------------------------------------
   *        ExecutePlan
   *
*************** ExecutePlan(EState *estate,
*** 1487,1492 ****
--- 1637,1645 ----
       */
      for (;;)
      {
+         Datum tts_rowacl = PointerGetDatum(NULL);
+         Datum tts_seclabel = PointerGetDatum(NULL);
+
          /* Reset the per-output-tuple exprcontext */
          ResetPerTupleExprContext(estate);

*************** lnext:    ;
*** 1631,1636 ****
--- 1784,1795 ----
              }

              /*
+              * extract writable system attribute
+              */
+             fetchWritableSystemAttribute(junkfilter, slot,
+                                          &tts_rowacl, &tts_seclabel);
+
+             /*
               * extract the 'ctid' junk attribute.
               */
              if (operation == CMD_UPDATE || operation == CMD_DELETE)
*************** lnext:    ;
*** 1657,1662 ****
--- 1816,1823 ----
              if (operation != CMD_DELETE)
                  slot = ExecFilterJunk(junkfilter, slot);
          }
+         slot->tts_rowacl = tts_rowacl;
+         slot->tts_seclabel = tts_seclabel;

          /*
           * now that we have a tuple, do the appropriate thing with it.. either
*************** ExecInsert(TupleTableSlot *slot,
*** 1766,1771 ****
--- 1927,1934 ----
      resultRelInfo = estate->es_result_relation_info;
      resultRelationDesc = resultRelInfo->ri_RelationDesc;

+     storeWritableSystemAttribute(resultRelationDesc, slot, tuple);
+
      /* BEFORE ROW INSERT Triggers */
      if (resultRelInfo->ri_TrigDesc &&
          resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
*************** ExecInsert(TupleTableSlot *slot,
*** 1802,1807 ****
--- 1965,1977 ----
          ExecConstraints(resultRelInfo, slot, estate);

      /*
+      * Mandatory access controls of the tuple
+      */
+     if (!pgaceHeapTupleInsert(resultRelationDesc, tuple,
+                               false, !!resultRelInfo->ri_projectReturning))
+         return;
+
+     /*
       * insert the tuple
       *
       * Note: heap_insert returns the tid (location) of the new tuple in the
*************** ExecDelete(ItemPointer tupleid,
*** 1867,1872 ****
--- 2037,2046 ----
              return;
      }

+     if (!pgaceHeapTupleDelete(resultRelationDesc, tupleid,
+                               false, !!resultRelInfo->ri_projectReturning))
+         return;
+
      /*
       * delete the tuple
       *
*************** ExecUpdate(TupleTableSlot *slot,
*** 2003,2008 ****
--- 2177,2184 ----
      resultRelInfo = estate->es_result_relation_info;
      resultRelationDesc = resultRelInfo->ri_RelationDesc;

+     storeWritableSystemAttribute(resultRelationDesc, slot, tuple);
+
      /* BEFORE ROW UPDATE Triggers */
      if (resultRelInfo->ri_TrigDesc &&
          resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
*************** lreplace:;
*** 2047,2052 ****
--- 2223,2235 ----
          ExecConstraints(resultRelInfo, slot, estate);

      /*
+      * Mandatory access controls of the tuple
+      */
+     if (!pgaceHeapTupleUpdate(resultRelationDesc, tupleid, tuple,
+                               false, !!resultRelInfo->ri_projectReturning))
+         return;
+
+     /*
       * replace the heap tuple
       *
       * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
*************** OpenIntoRel(QueryDesc *queryDesc)
*** 2911,2917 ****
                                                0,
                                                into->onCommit,
                                                reloptions,
!                                               allowSystemTableMods);

      FreeTupleDesc(tupdesc);

--- 3094,3101 ----
                                                0,
                                                into->onCommit,
                                                reloptions,
!                                               allowSystemTableMods,
!                                               NIL);

      FreeTupleDesc(tupdesc);

*************** intorel_receive(TupleTableSlot *slot, De
*** 3021,3026 ****
--- 3205,3217 ----
       */
      tuple = ExecMaterializeSlot(slot);

+     storeWritableSystemAttribute(myState->rel, slot, tuple);
+     if (!pgaceHeapTupleInsert(myState->rel, tuple, false, false))
+     {
+         heap_freetuple(tuple);
+         return;
+     }
+
      heap_insert(myState->rel,
                  tuple,
                  myState->estate->es_output_cid,
diff -Nrpc base/src/backend/executor/execQual.c sepgsql/src/backend/executor/execQual.c
*** base/src/backend/executor/execQual.c    Tue Jan 13 09:22:28 2009
--- sepgsql/src/backend/executor/execQual.c    Fri Jan 16 17:05:27 2009
***************
*** 47,52 ****
--- 47,53 ----
  #include "nodes/nodeFuncs.h"
  #include "optimizer/planner.h"
  #include "pgstat.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
*************** init_fcache(Oid foid, FuncExprState *fca
*** 1047,1052 ****
--- 1048,1054 ----
      /* Set up the primary fmgr lookup information */
      fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
      fcache->func.fn_expr = (Node *) fcache->xprstate.expr;
+     pgaceCallFunction(&fcache->func);

      /* If function returns set, prepare expected tuple descriptor */
      if (fcache->func.fn_retset && needDescForSets)
*************** ExecEvalArrayCoerceExpr(ArrayCoerceExprS
*** 4014,4019 ****
--- 4016,4023 ----

          /* Initialize additional info */
          astate->elemfunc.fn_expr = (Node *) acoerce;
+
+         pgaceCallFunction(&astate->elemfunc);
      }

      /*
diff -Nrpc base/src/backend/executor/execScan.c sepgsql/src/backend/executor/execScan.c
*** base/src/backend/executor/execScan.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/execScan.c    Sat Jan  3 15:58:18 2009
***************
*** 20,25 ****
--- 20,26 ----

  #include "executor/executor.h"
  #include "miscadmin.h"
+ #include "security/pgace.h"
  #include "utils/memutils.h"


*************** TupleTableSlot *
*** 48,54 ****
  ExecScan(ScanState *node,
           ExecScanAccessMtd accessMtd)    /* function returning a tuple */
  {
!     ExprContext *econtext;
      List       *qual;
      ProjectionInfo *projInfo;
      ExprDoneCond isDone;
--- 49,55 ----
  ExecScan(ScanState *node,
           ExecScanAccessMtd accessMtd)    /* function returning a tuple */
  {
!     ExprContext *econtext = node->ps.ps_ExprContext;
      List       *qual;
      ProjectionInfo *projInfo;
      ExprDoneCond isDone;
*************** ExecScan(ScanState *node,
*** 65,71 ****
       * all the overhead and return the raw scan tuple.
       */
      if (!qual && !projInfo)
!         return (*accessMtd) (node);

      /*
       * Check to see if we're still projecting out tuples from a previous scan
--- 66,87 ----
       * all the overhead and return the raw scan tuple.
       */
      if (!qual && !projInfo)
!     {
!         while (true)
!         {
!             resultSlot = (*accessMtd) (node);
!
!             if (TupIsNull(resultSlot))
!                 break;
!
!             if (pgaceExecScan((Scan *)node->ps.plan,
!                               node->ss_currentRelation, resultSlot))
!                 break;
!
!             ResetExprContext(econtext);
!         }
!         return resultSlot;
!     }

      /*
       * Check to see if we're still projecting out tuples from a previous scan
*************** ExecScan(ScanState *node,
*** 87,93 ****
       * storage allocated in the previous tuple cycle.  Note this can't happen
       * until we're done projecting out tuples from a scan tuple.
       */
-     econtext = node->ps.ps_ExprContext;
      ResetExprContext(econtext);

      /*
--- 103,108 ----
*************** ExecScan(ScanState *node,
*** 127,134 ****
           * check for non-nil qual here to avoid a function call to ExecQual()
           * when the qual is nil ... saves only a few cycles, but they add up
           * ...
           */
!         if (!qual || ExecQual(qual, econtext, false))
          {
              /*
               * Found a satisfactory scan tuple.
--- 142,152 ----
           * check for non-nil qual here to avoid a function call to ExecQual()
           * when the qual is nil ... saves only a few cycles, but they add up
           * ...
+          * And security check for tuple level access controls at the last.
           */
!         if ((!qual || ExecQual(qual, econtext, false))
!             && pgaceExecScan((Scan *)node->ps.plan,
!                              node->ss_currentRelation, slot))
          {
              /*
               * Found a satisfactory scan tuple.
*************** tlist_matches_tupdesc(PlanState *ps, Lis
*** 197,202 ****
--- 215,222 ----
      int            numattrs = tupdesc->natts;
      int            attrno;
      bool        hasoid;
+     bool        hasrowacl;
+     bool        hasseclabel;
      ListCell   *tlist_item = list_head(tlist);

      /* Check the tlist attributes */
*************** tlist_matches_tupdesc(PlanState *ps, Lis
*** 240,251 ****
          return false;            /* tlist too long */

      /*
!      * If the plan context requires a particular hasoid setting, then that has
!      * to match, too.
       */
      if (ExecContextForcesOids(ps, &hasoid) &&
          hasoid != tupdesc->tdhasoid)
          return false;

      return true;
  }
--- 260,279 ----
          return false;            /* tlist too long */

      /*
!      * If the plan context requires a particular hasoid/hassecurity setting,
!      * then they have to match, too.
       */
      if (ExecContextForcesOids(ps, &hasoid) &&
          hasoid != tupdesc->tdhasoid)
          return false;

+     if (ExecContextForcesRowAcl(ps, &hasrowacl) &&
+         hasrowacl != tupdesc->tdhasrowacl)
+         return false;
+
+     if (ExecContextForcesSecLabel(ps, &hasseclabel) &&
+         hasseclabel != tupdesc->tdhasseclabel)
+         return false;
+
      return true;
  }
diff -Nrpc base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/execTuples.c
*** base/src/backend/executor/execTuples.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/execTuples.c    Sat Jan  3 15:58:18 2009
***************
*** 99,106 ****
  #include "utils/typcache.h"


! static TupleDesc ExecTypeFromTLInternal(List *targetList,
!                        bool hasoid, bool skipjunk);


  /* ----------------------------------------------------------------
--- 99,106 ----
  #include "utils/typcache.h"


! static TupleDesc ExecTypeFromTLInternal(List *targetList, bool hasoid,
!                                         bool hasrowacl, bool hasseclabel, bool skipjunk);


  /* ----------------------------------------------------------------
*************** ExecInitNullTupleSlot(EState *estate, Tu
*** 948,956 ****
   * ----------------------------------------------------------------
   */
  TupleDesc
! ExecTypeFromTL(List *targetList, bool hasoid)
  {
!     return ExecTypeFromTLInternal(targetList, hasoid, false);
  }

  /* ----------------------------------------------------------------
--- 948,957 ----
   * ----------------------------------------------------------------
   */
  TupleDesc
! ExecTypeFromTL(List *targetList, bool hasoid, bool hasrowacl, bool hasseclabel)
  {
!     return ExecTypeFromTLInternal(targetList,
!                                   hasoid, hasrowacl, hasseclabel, false);
  }

  /* ----------------------------------------------------------------
*************** ExecTypeFromTL(List *targetList, bool ha
*** 960,972 ****
   * ----------------------------------------------------------------
   */
  TupleDesc
! ExecCleanTypeFromTL(List *targetList, bool hasoid)
  {
!     return ExecTypeFromTLInternal(targetList, hasoid, true);
  }

  static TupleDesc
! ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk)
  {
      TupleDesc    typeInfo;
      ListCell   *l;
--- 961,975 ----
   * ----------------------------------------------------------------
   */
  TupleDesc
! ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasrowacl, bool hasseclabel)
  {
!     return ExecTypeFromTLInternal(targetList,
!                                   hasoid, hasrowacl, hasseclabel, true);
  }

  static TupleDesc
! ExecTypeFromTLInternal(List *targetList,
!                        bool hasoid, bool hasrowacl, bool hasseclabel, bool skipjunk)
  {
      TupleDesc    typeInfo;
      ListCell   *l;
*************** ExecTypeFromTLInternal(List *targetList,
*** 978,983 ****
--- 981,988 ----
      else
          len = ExecTargetListLength(targetList);
      typeInfo = CreateTemplateTupleDesc(len, hasoid);
+     typeInfo->tdhasrowacl = hasrowacl;
+     typeInfo->tdhasseclabel = hasseclabel;

      foreach(l, targetList)
      {
diff -Nrpc base/src/backend/executor/execUtils.c sepgsql/src/backend/executor/execUtils.c
*** base/src/backend/executor/execUtils.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/execUtils.c    Sat Jan  3 15:58:18 2009
*************** void
*** 504,509 ****
--- 504,511 ----
  ExecAssignResultTypeFromTL(PlanState *planstate)
  {
      bool        hasoid;
+     bool        hassecacl;
+     bool        hasseclabel;
      TupleDesc    tupDesc;

      if (ExecContextForcesOids(planstate, &hasoid))
*************** ExecAssignResultTypeFromTL(PlanState *pl
*** 516,527 ****
          hasoid = false;
      }

      /*
       * ExecTypeFromTL needs the parse-time representation of the tlist, not a
       * list of ExprStates.    This is good because some plan nodes don't bother
       * to set up planstate->targetlist ...
       */
!     tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
      ExecAssignResultType(planstate, tupDesc);
  }

--- 518,535 ----
          hasoid = false;
      }

+     if (!ExecContextForcesRowAcl(planstate, &hassecacl))
+         hassecacl = false;
+     if (!ExecContextForcesSecLabel(planstate, &hasseclabel))
+         hasseclabel = false;
+
      /*
       * ExecTypeFromTL needs the parse-time representation of the tlist, not a
       * list of ExprStates.    This is good because some plan nodes don't bother
       * to set up planstate->targetlist ...
       */
!     tupDesc = ExecTypeFromTL(planstate->plan->targetlist,
!                              hasoid, hassecacl, hasseclabel);
      ExecAssignResultType(planstate, tupDesc);
  }

diff -Nrpc base/src/backend/executor/functions.c sepgsql/src/backend/executor/functions.c
*** base/src/backend/executor/functions.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/functions.c    Sat Jan  3 15:58:18 2009
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1134,1140 ****

          /* Set up junk filter if needed */
          if (junkFilter)
!             *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
      }
      else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
      {
--- 1134,1140 ----

          /* Set up junk filter if needed */
          if (junkFilter)
!             *junkFilter = ExecInitJunkFilter(tlist, false, false, false, NULL);
      }
      else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
      {
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1166,1172 ****
                                                           COERCE_DONTCARE);
                  /* Set up junk filter if needed */
                  if (junkFilter)
!                     *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
                  return false;    /* NOT returning whole tuple */
              }
          }
--- 1166,1172 ----
                                                           COERCE_DONTCARE);
                  /* Set up junk filter if needed */
                  if (junkFilter)
!                     *junkFilter = ExecInitJunkFilter(tlist, false, false, false, NULL);
                  return false;    /* NOT returning whole tuple */
              }
          }
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1179,1185 ****
               * what the caller expects will happen at runtime.
               */
              if (junkFilter)
!                 *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
              return true;
          }
          Assert(tupdesc);
--- 1179,1185 ----
               * what the caller expects will happen at runtime.
               */
              if (junkFilter)
!                 *junkFilter = ExecInitJunkFilter(tlist, false, false, false, NULL);
              return true;
          }
          Assert(tupdesc);
diff -Nrpc base/src/backend/executor/nodeAgg.c sepgsql/src/backend/executor/nodeAgg.c
*** base/src/backend/executor/nodeAgg.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/nodeAgg.c    Fri Jan 16 17:05:27 2009
***************
*** 79,84 ****
--- 79,85 ----
  #include "parser/parse_agg.h"
  #include "parser/parse_coerce.h"
  #include "parser/parse_oper.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
*************** ExecInitAgg(Agg *node, EState *estate, i
*** 1430,1435 ****
--- 1431,1438 ----
              aclcheck_error(aclresult, ACL_KIND_PROC,
                             get_func_name(aggref->aggfnoid));

+         pgaceCallAggFunction(aggTuple);
+
          peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
          peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;

*************** ExecInitAgg(Agg *node, EState *estate, i
*** 1493,1503 ****
--- 1496,1508 ----

          fmgr_info(transfn_oid, &peraggstate->transfn);
          peraggstate->transfn.fn_expr = (Node *) transfnexpr;
+         pgaceCallFunction(&peraggstate->transfn);

          if (OidIsValid(finalfn_oid))
          {
              fmgr_info(finalfn_oid, &peraggstate->finalfn);
              peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
+             pgaceCallFunction(&peraggstate->finalfn);
          }

          get_typlenbyval(aggref->aggtype,
diff -Nrpc base/src/backend/executor/nodeMergejoin.c sepgsql/src/backend/executor/nodeMergejoin.c
*** base/src/backend/executor/nodeMergejoin.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/nodeMergejoin.c    Fri Jan 16 17:05:27 2009
***************
*** 98,103 ****
--- 98,104 ----
  #include "executor/execdefs.h"
  #include "executor/nodeMergejoin.h"
  #include "miscadmin.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/lsyscache.h"
  #include "utils/memutils.h"
*************** MJExamineQuals(List *mergeclauses,
*** 218,223 ****
--- 219,225 ----

          /* Set up the fmgr lookup information */
          fmgr_info(cmpproc, &(clause->cmpfinfo));
+         pgaceCallFunction(&clause->cmpfinfo);

          /* Fill the additional comparison-strategy flags */
          if (opstrategy == BTLessStrategyNumber)
diff -Nrpc base/src/backend/executor/nodeSubplan.c sepgsql/src/backend/executor/nodeSubplan.c
*** base/src/backend/executor/nodeSubplan.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/nodeSubplan.c    Sat Jan  3 15:58:18 2009
*************** ExecInitSubPlan(SubPlan *subplan, PlanSt
*** 869,875 ****
           * (hack alert!).  The righthand expressions will be evaluated in our
           * own innerecontext.
           */
!         tupDesc = ExecTypeFromTL(leftptlist, false);
          slot = ExecAllocTableSlot(tupTable);
          ExecSetSlotDescriptor(slot, tupDesc);
          sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
--- 869,875 ----
           * (hack alert!).  The righthand expressions will be evaluated in our
           * own innerecontext.
           */
!         tupDesc = ExecTypeFromTL(leftptlist, false, false, false);
          slot = ExecAllocTableSlot(tupTable);
          ExecSetSlotDescriptor(slot, tupDesc);
          sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
*************** ExecInitSubPlan(SubPlan *subplan, PlanSt
*** 877,883 ****
                                                     slot,
                                                     NULL);

!         tupDesc = ExecTypeFromTL(rightptlist, false);
          slot = ExecAllocTableSlot(tupTable);
          ExecSetSlotDescriptor(slot, tupDesc);
          sstate->projRight = ExecBuildProjectionInfo(righttlist,
--- 877,883 ----
                                                     slot,
                                                     NULL);

!         tupDesc = ExecTypeFromTL(rightptlist, false, false, false);
          slot = ExecAllocTableSlot(tupTable);
          ExecSetSlotDescriptor(slot, tupDesc);
          sstate->projRight = ExecBuildProjectionInfo(righttlist,
diff -Nrpc base/src/backend/executor/nodeWindowAgg.c sepgsql/src/backend/executor/nodeWindowAgg.c
*** base/src/backend/executor/nodeWindowAgg.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/executor/nodeWindowAgg.c    Fri Jan 16 17:05:27 2009
***************
*** 43,48 ****
--- 43,49 ----
  #include "optimizer/clauses.h"
  #include "parser/parse_agg.h"
  #include "parser/parse_coerce.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/datum.h"
*************** ExecInitWindowAgg(WindowAgg *node, EStat
*** 1231,1236 ****
--- 1232,1238 ----
          fmgr_info_cxt(wfunc->winfnoid, &perfuncstate->flinfo,
                        tmpcontext->ecxt_per_query_memory);
          perfuncstate->flinfo.fn_expr = (Node *) wfunc;
+         pgaceCallFunction(&perfuncstate->flinfo);
          get_typlenbyval(wfunc->wintype,
                          &perfuncstate->resulttypeLen,
                          &perfuncstate->resulttypeByVal);
*************** initialize_peragg(WindowAggState *winsta
*** 1457,1467 ****
--- 1459,1471 ----

      fmgr_info(transfn_oid, &peraggstate->transfn);
      peraggstate->transfn.fn_expr = (Node *) transfnexpr;
+     pgaceCallFunction(&peraggstate->transfn);

      if (OidIsValid(finalfn_oid))
      {
          fmgr_info(finalfn_oid, &peraggstate->finalfn);
          peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
+         pgaceCallFunction(&peraggstate->finalfn);
      }

      get_typlenbyval(wfunc->wintype,
diff -Nrpc base/src/backend/executor/spi.c sepgsql/src/backend/executor/spi.c
*** base/src/backend/executor/spi.c    Thu Jan 22 14:34:54 2009
--- sepgsql/src/backend/executor/spi.c    Thu Jan 22 14:41:23 2009
*************** SPI_modifytuple(Relation rel, HeapTuple
*** 705,710 ****
--- 705,714 ----
          mtuple->t_tableOid = tuple->t_tableOid;
          if (rel->rd_att->tdhasoid)
              HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
+         if (HeapTupleHasRowAcl(mtuple))
+             HeapTupleSetRowAcl(mtuple, HeapTupleGetRowAcl(tuple));
+         if (HeapTupleHasSecLabel(mtuple))
+             HeapTupleSetSecLabel(mtuple, HeapTupleGetSecLabel(tuple));
      }
      else
      {
diff -Nrpc base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fsstubs.c
*** base/src/backend/libpq/be-fsstubs.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/libpq/be-fsstubs.c    Sat Jan  3 15:58:18 2009
***************
*** 45,50 ****
--- 45,51 ----
  #include "libpq/be-fsstubs.h"
  #include "libpq/libpq-fs.h"
  #include "miscadmin.h"
+ #include "security/pgace.h"
  #include "storage/fd.h"
  #include "storage/large_object.h"
  #include "utils/builtins.h"
*************** lo_read(int fd, char *buf, int len)
*** 156,161 ****
--- 157,164 ----
                  (errcode(ERRCODE_UNDEFINED_OBJECT),
                   errmsg("invalid large-object descriptor: %d", fd)));

+     pgaceLargeObjectRead(cookies[fd], len);
+
      status = inv_read(cookies[fd], buf, len);

      return status;
*************** lo_write(int fd, const char *buf, int le
*** 177,182 ****
--- 180,187 ----
                errmsg("large object descriptor %d was not opened for writing",
                       fd)));

+     pgaceLargeObjectWrite(cookies[fd], len);
+
      status = inv_write(cookies[fd], buf, len);

      return status;
*************** lo_import_internal(text *filename, Oid l
*** 377,382 ****
--- 382,392 ----
      oid = inv_create(lobjOid);

      /*
+      * check permission to import a file into this object
+      */
+     pgaceLargeObjectImport(oid, FileRawDescriptor(fd), fnamebuf);
+
+     /*
       * read in from the filesystem and write to the inversion object
       */
      lobj = inv_open(oid, INV_WRITE, fscxt);
*************** lo_export(PG_FUNCTION_ARGS)
*** 447,452 ****
--- 457,466 ----
                  (errcode_for_file_access(),
                   errmsg("could not create server file \"%s\": %m",
                          fnamebuf)));
+     /*
+      * check permission to export this object into a file
+      */
+     pgaceLargeObjectExport(lobjId, FileRawDescriptor(fd), fnamebuf);

      /*
       * read in from the inversion file and write to the filesystem
*************** lo_truncate(PG_FUNCTION_ARGS)
*** 482,487 ****
--- 496,503 ----
                  (errcode(ERRCODE_UNDEFINED_OBJECT),
                   errmsg("invalid large-object descriptor: %d", fd)));

+     pgaceLargeObjectTruncate(cookies[fd], len);
+
      inv_truncate(cookies[fd], len);

      PG_RETURN_INT32(0);
diff -Nrpc base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c
*** base/src/backend/nodes/copyfuncs.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/nodes/copyfuncs.c    Fri Jan 23 10:55:35 2009
***************
*** 24,29 ****
--- 24,30 ----

  #include "nodes/plannodes.h"
  #include "nodes/relation.h"
+ #include "nodes/security.h"
  #include "utils/datum.h"


*************** _copyPlannedStmt(PlannedStmt *from)
*** 90,95 ****
--- 91,97 ----
      COPY_NODE_FIELD(relationOids);
      COPY_NODE_FIELD(invalItems);
      COPY_SCALAR_FIELD(nParamExec);
+     COPY_NODE_FIELD(pgaceItem);

      return newnode;
  }
*************** CopyScanFields(Scan *from, Scan *newnode
*** 259,264 ****
--- 261,267 ----
      CopyPlanFields((Plan *) from, (Plan *) newnode);

      COPY_SCALAR_FIELD(scanrelid);
+     COPY_SCALAR_FIELD(pgaceTuplePerms);
  }

  /*
*************** _copyRangeTblEntry(RangeTblEntry *from)
*** 1742,1747 ****
--- 1745,1751 ----
      COPY_SCALAR_FIELD(checkAsUser);
      COPY_BITMAPSET_FIELD(selectedCols);
      COPY_BITMAPSET_FIELD(modifiedCols);
+     COPY_SCALAR_FIELD(pgaceTuplePerms);

      return newnode;
  }
*************** _copyColumnDef(ColumnDef *from)
*** 2083,2088 ****
--- 2087,2093 ----
      COPY_NODE_FIELD(raw_default);
      COPY_STRING_FIELD(cooked_default);
      COPY_NODE_FIELD(constraints);
+     COPY_NODE_FIELD(pgaceItem);

      return newnode;
  }
*************** _copyQuery(Query *from)
*** 2180,2185 ****
--- 2185,2191 ----
      COPY_NODE_FIELD(limitCount);
      COPY_NODE_FIELD(rowMarks);
      COPY_NODE_FIELD(setOperations);
+     COPY_NODE_FIELD(pgaceItem);

      return newnode;
  }
*************** _copyCreateStmt(CreateStmt *from)
*** 2431,2436 ****
--- 2437,2443 ----
      COPY_NODE_FIELD(options);
      COPY_SCALAR_FIELD(oncommit);
      COPY_STRING_FIELD(tablespacename);
+     COPY_NODE_FIELD(pgaceItem);

      return newnode;
  }
*************** _copyValue(Value *from)
*** 3438,3443 ****
--- 3445,3470 ----
      return newnode;
  }

+ /* ****************************************************************
+  *                    nodes/security.h copy functions
+  * ****************************************************************
+  */
+ static SelinuxEvalItem *
+ _copySelinuxEvalItem(SelinuxEvalItem *from)
+ {
+     SelinuxEvalItem *newnode = makeNode(SelinuxEvalItem);
+     int n;
+
+     COPY_SCALAR_FIELD(relid);
+     COPY_SCALAR_FIELD(inh);
+
+     COPY_SCALAR_FIELD(relperms);
+     COPY_SCALAR_FIELD(nattrs);
+     COPY_POINTER_FIELD(attperms, from->nattrs * sizeof(uint32));
+
+     return newnode;
+ }
+
  /*
   * copyObject
   *
*************** copyObject(void *from)
*** 4115,4120 ****
--- 4142,4150 ----
          case T_XmlSerialize:
              retval = _copyXmlSerialize(from);
              break;
+         case T_SelinuxEvalItem:
+             retval = _copySelinuxEvalItem(from);
+             break;

          default:
              elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff -Nrpc base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalfuncs.c
*** base/src/backend/nodes/equalfuncs.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/nodes/equalfuncs.c    Fri Jan 23 10:55:35 2009
***************
*** 30,35 ****
--- 30,36 ----
  #include "postgres.h"

  #include "nodes/relation.h"
+ #include "nodes/security.h"
  #include "utils/datum.h"


*************** _equalQuery(Query *a, Query *b)
*** 871,876 ****
--- 872,878 ----
      COMPARE_NODE_FIELD(limitCount);
      COMPARE_NODE_FIELD(rowMarks);
      COMPARE_NODE_FIELD(setOperations);
+     COMPARE_NODE_FIELD(pgaceItem);

      return true;
  }
*************** _equalCreateStmt(CreateStmt *a, CreateSt
*** 1086,1091 ****
--- 1088,1094 ----
      COMPARE_NODE_FIELD(options);
      COMPARE_SCALAR_FIELD(oncommit);
      COMPARE_STRING_FIELD(tablespacename);
+     COMPARE_NODE_FIELD(pgaceItem);

      return true;
  }
*************** _equalColumnDef(ColumnDef *a, ColumnDef
*** 2062,2067 ****
--- 2065,2071 ----
      COMPARE_NODE_FIELD(raw_default);
      COMPARE_STRING_FIELD(cooked_default);
      COMPARE_NODE_FIELD(constraints);
+     COMPARE_NODE_FIELD(pgaceItem);

      return true;
  }
*************** _equalXmlSerialize(XmlSerialize *a, XmlS
*** 2229,2234 ****
--- 2233,2253 ----
  }

  /*
+  * Stuff from nodes/security.h
+  */
+ static bool
+ _equalSelinuxEvalItem(SelinuxEvalItem *a, SelinuxEvalItem *b)
+ {
+     COMPARE_SCALAR_FIELD(relid);
+     COMPARE_SCALAR_FIELD(inh);
+     COMPARE_SCALAR_FIELD(relperms);
+     COMPARE_SCALAR_FIELD(nattrs);
+     COMPARE_POINTER_FIELD(attperms, a->nattrs * sizeof(uint32));
+
+     return true;
+ }
+
+ /*
   * Stuff from pg_list.h
   */

*************** equal(void *a, void *b)
*** 2891,2896 ****
--- 2910,2918 ----
          case T_XmlSerialize:
              retval = _equalXmlSerialize(a, b);
              break;
+         case T_SelinuxEvalItem:
+             retval = _equalSelinuxEvalItem(a, b);
+             break;

          default:
              elog(ERROR, "unrecognized node type: %d",
diff -Nrpc base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c
*** base/src/backend/nodes/outfuncs.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/nodes/outfuncs.c    Fri Jan 23 10:55:35 2009
***************
*** 26,31 ****
--- 26,32 ----
  #include "lib/stringinfo.h"
  #include "nodes/plannodes.h"
  #include "nodes/relation.h"
+ #include "nodes/security.h"
  #include "utils/datum.h"


*************** _outPlannedStmt(StringInfo str, PlannedS
*** 255,260 ****
--- 256,262 ----
      WRITE_NODE_FIELD(relationOids);
      WRITE_NODE_FIELD(invalItems);
      WRITE_INT_FIELD(nParamExec);
+     WRITE_NODE_FIELD(pgaceItem);
  }

  /*
*************** _outScanInfo(StringInfo str, Scan *node)
*** 285,290 ****
--- 287,293 ----
      _outPlanInfo(str, (Plan *) node);

      WRITE_UINT_FIELD(scanrelid);
+     WRITE_UINT_FIELD(pgaceTuplePerms);
  }

  /*
*************** _outRelOptInfo(StringInfo str, RelOptInf
*** 1526,1531 ****
--- 1529,1535 ----
      WRITE_BOOL_FIELD(has_eclass_joins);
      WRITE_BITMAPSET_FIELD(index_outer_relids);
      WRITE_NODE_FIELD(index_inner_paths);
+     WRITE_UINT_FIELD(pgaceTuplePerms);
  }

  static void
*************** _outCreateStmt(StringInfo str, CreateStm
*** 1718,1723 ****
--- 1722,1728 ----
      WRITE_NODE_FIELD(options);
      WRITE_ENUM_FIELD(oncommit, OnCommitAction);
      WRITE_STRING_FIELD(tablespacename);
+     WRITE_NODE_FIELD(pgaceItem);
  }

  static void
*************** _outColumnDef(StringInfo str, ColumnDef
*** 1838,1843 ****
--- 1843,1849 ----
      WRITE_NODE_FIELD(raw_default);
      WRITE_STRING_FIELD(cooked_default);
      WRITE_NODE_FIELD(constraints);
+     WRITE_NODE_FIELD(pgaceItem);
  }

  static void
*************** _outQuery(StringInfo str, Query *node)
*** 1932,1937 ****
--- 1938,1944 ----
      WRITE_NODE_FIELD(limitCount);
      WRITE_NODE_FIELD(rowMarks);
      WRITE_NODE_FIELD(setOperations);
+     WRITE_NODE_FIELD(pgaceItem);
  }

  static void
*************** _outRangeTblEntry(StringInfo str, RangeT
*** 2060,2065 ****
--- 2067,2073 ----
      WRITE_OID_FIELD(checkAsUser);
      WRITE_BITMAPSET_FIELD(selectedCols);
      WRITE_BITMAPSET_FIELD(modifiedCols);
+     WRITE_UINT_FIELD(pgaceTuplePerms);
  }

  static void
*************** _outFkConstraint(StringInfo str, FkConst
*** 2332,2337 ****
--- 2340,2368 ----
      WRITE_BOOL_FIELD(skip_validation);
  }

+ /*****************************************************************************
+  *
+  *    Stuff from nodes/security.h
+  *
+  *****************************************************************************/
+ static void
+ _outSelinuxEvalItem(StringInfo str, SelinuxEvalItem *node)
+ {
+     int i;
+
+     WRITE_NODE_TYPE("SELINUXEVALITEM");
+
+     WRITE_OID_FIELD(relid);
+     WRITE_BOOL_FIELD(inh);
+
+     WRITE_UINT_FIELD(relperms);
+     WRITE_UINT_FIELD(nattrs);
+
+     appendStringInfo(str, " :attperms [");
+     for (i = 0; i < node->nattrs; i++)
+         appendStringInfo(str, " %u", node->attperms[i]);
+     appendStringInfo(str, " ]");
+ }

  /*
   * _outNode -
*************** _outNode(StringInfo str, void *obj)
*** 2776,2781 ****
--- 2807,2815 ----
              case T_XmlSerialize:
                  _outXmlSerialize(str, obj);
                  break;
+             case T_SelinuxEvalItem:
+                 _outSelinuxEvalItem(str, obj);
+                 break;

              default:

diff -Nrpc base/src/backend/nodes/readfuncs.c sepgsql/src/backend/nodes/readfuncs.c
*** base/src/backend/nodes/readfuncs.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/nodes/readfuncs.c    Fri Jan 23 10:55:35 2009
***************
*** 30,35 ****
--- 30,36 ----

  #include "nodes/parsenodes.h"
  #include "nodes/readfuncs.h"
+ #include "nodes/security.h"


  /*
*************** _readQuery(void)
*** 216,221 ****
--- 217,223 ----
      READ_NODE_FIELD(limitCount);
      READ_NODE_FIELD(rowMarks);
      READ_NODE_FIELD(setOperations);
+     READ_NODE_FIELD(pgaceItem);

      READ_DONE();
  }
*************** _readRangeTblEntry(void)
*** 1149,1158 ****
--- 1151,1199 ----
      READ_OID_FIELD(checkAsUser);
      READ_BITMAPSET_FIELD(selectedCols);
      READ_BITMAPSET_FIELD(modifiedCols);
+     READ_UINT_FIELD(pgaceTuplePerms);

      READ_DONE();
  }

+ /*
+  * Stuff from nodes/security.h
+  */
+ static SelinuxEvalItem *
+ _readSelinuxEvalItem(void)
+ {
+     int i;
+
+     READ_LOCALS(SelinuxEvalItem);
+
+     READ_OID_FIELD(relid);
+     READ_BOOL_FIELD(inh);
+
+     READ_UINT_FIELD(relperms);
+     READ_UINT_FIELD(nattrs);
+
+     /*
+      * TODO: This part should be moved to readArray() ?
+      */
+     local_node->attperms = palloc0(local_node->nattrs * sizeof(uint32));
+
+     token = pg_strtok(&length);    /* skip :attperms */
+     token = pg_strtok(&length);    /* read '[' */
+     if (token == NULL || strcmp(token, "[") != 0)
+         elog(ERROR, "expected \"[\" to start array, but got \"%s\"",
+              token ? (const char *) token : "[NULL]");
+     for (i = 0; i < local_node->nattrs; i++)
+     {
+         token = pg_strtok(&length);
+         local_node->attperms[i] = atoui(token);
+     }
+     token = pg_strtok(&length);    /* read ']' */
+     if (token == NULL || strcmp(token, "[") != 0)
+         elog(ERROR, "expected \"[\" to end array, but got \"%s\"",
+              token ? (const char *) token : "[NULL]");
+
+     READ_DONE();
+ }

  /*
   * parseNodeString
*************** parseNodeString(void)
*** 1274,1279 ****
--- 1315,1322 ----
          return_value = _readNotifyStmt();
      else if (MATCH("DECLARECURSOR", 13))
          return_value = _readDeclareCursorStmt();
+     else if (MATCH("SELINUXEVALITEM", 15))
+         return_value = _readSelinuxEvalItem();
      else
      {
          elog(ERROR, "badly formatted node string \"%.32s\"...", token);
diff -Nrpc base/src/backend/optimizer/plan/createplan.c sepgsql/src/backend/optimizer/plan/createplan.c
*** base/src/backend/optimizer/plan/createplan.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/optimizer/plan/createplan.c    Sat Jan  3 15:58:18 2009
*************** create_scan_plan(PlannerInfo *root, Path
*** 302,307 ****
--- 302,313 ----
      }

      /*
+      * The guest of PGACE can refer plan->pgaceTuplePerms to apply
+      * tuple level access control in the pgaceExecScan() hook.
+      */
+     ((Scan *)plan)->pgaceTuplePerms = rel->pgaceTuplePerms;
+
+     /*
       * If there are any pseudoconstant clauses attached to this node, insert a
       * gating Result node that evaluates the pseudoconstants as one-time
       * quals.
diff -Nrpc base/src/backend/optimizer/plan/planner.c sepgsql/src/backend/optimizer/plan/planner.c
*** base/src/backend/optimizer/plan/planner.c    Tue Jan 13 09:22:28 2009
--- sepgsql/src/backend/optimizer/plan/planner.c    Tue Jan 13 09:39:35 2009
*************** standard_planner(Query *parse, int curso
*** 230,235 ****
--- 230,236 ----
      result->relationOids = glob->relationOids;
      result->invalItems = glob->invalItems;
      result->nParamExec = list_length(glob->paramlist);
+     result->pgaceItem = parse->pgaceItem;

      return result;
  }
diff -Nrpc base/src/backend/optimizer/util/clauses.c sepgsql/src/backend/optimizer/util/clauses.c
*** base/src/backend/optimizer/util/clauses.c    Tue Jan 13 09:22:28 2009
--- sepgsql/src/backend/optimizer/util/clauses.c    Tue Jan 13 09:39:35 2009
***************
*** 38,43 ****
--- 38,44 ----
  #include "parser/parse_coerce.h"
  #include "parser/parse_func.h"
  #include "rewrite/rewriteManip.h"
+ #include "security/pgace.h"
  #include "tcop/tcopprot.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
*************** inline_function(Oid funcid, Oid result_t
*** 3548,3553 ****
--- 3549,3557 ----
      if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK)
          return NULL;

+     if (!pgaceAllowFunctionInlined(funcid, func_tuple))
+         return NULL;
+
      /*
       * Setup error traceback support for ereport().  This is so that we can
       * finger the function that bad information came from.
*************** inline_set_returning_function(PlannerInf
*** 4005,4010 ****
--- 4009,4015 ----
          funcform->prosecdef ||
          !funcform->proretset ||
          !heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
+         !pgaceAllowFunctionInlined(fexpr->funcid, func_tuple) ||
          funcform->pronargs != list_length(fexpr->args))
      {
          ReleaseSysCache(func_tuple);
diff -Nrpc base/src/backend/optimizer/util/relnode.c sepgsql/src/backend/optimizer/util/relnode.c
*** base/src/backend/optimizer/util/relnode.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/optimizer/util/relnode.c    Sat Jan  3 15:58:18 2009
*************** build_simple_rel(PlannerInfo *root, int
*** 91,96 ****
--- 91,97 ----
      rel->has_eclass_joins = false;
      rel->index_outer_relids = NULL;
      rel->index_inner_paths = NIL;
+     rel->pgaceTuplePerms = rte->pgaceTuplePerms;

      /* Check type of rtable entry */
      switch (rte->rtekind)
diff -Nrpc base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze.c
*** base/src/backend/parser/analyze.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/parser/analyze.c    Fri Jan 23 10:55:35 2009
***************
*** 25,30 ****
--- 25,31 ----
  #include "postgres.h"

  #include "access/sysattr.h"
+ #include "catalog/heap.h"
  #include "catalog/pg_type.h"
  #include "nodes/makefuncs.h"
  #include "nodes/nodeFuncs.h"
***************
*** 39,44 ****
--- 40,46 ----
  #include "parser/parse_target.h"
  #include "parser/parsetree.h"
  #include "rewrite/rewriteManip.h"
+ #include "security/pgace.h"
  #include "utils/rel.h"


*************** transformInsertStmt(ParseState *pstate,
*** 651,657 ****
          tle = makeTargetEntry(expr,
                                attr_num,
                                col->name,
!                               false);
          qry->targetList = lappend(qry->targetList, tle);

          rte->modifiedCols = bms_add_member(rte->modifiedCols,
--- 653,659 ----
          tle = makeTargetEntry(expr,
                                attr_num,
                                col->name,
!                               attr_num < 0 ? true : false);
          qry->targetList = lappend(qry->targetList, tle);

          rte->modifiedCols = bms_add_member(rte->modifiedCols,
*************** transformInsertRow(ParseState *pstate, L
*** 766,771 ****
--- 768,814 ----
      return result;
  }

+ static void
+ transformSelectIntoSystemColumn(ParseState *pstate, Query *qry)
+ {
+     ListCell *l;
+     uint32 system_attrs = 0;
+     bool relhasoids
+         = interpretOidsOption(qry->intoClause->options);
+
+     foreach (l, qry->targetList) {
+         Form_pg_attribute attr;
+         TargetEntry *tle = lfirst(l);
+
+         if (tle->resjunk)
+             continue;
+
+         attr = SystemAttributeByName(tle->resname, relhasoids);
+         if (attr && SystemAttributeIsWritable(attr->attnum))
+         {
+             uint32 mask = (1<<(-attr->attnum));
+
+             /* duplication checks */
+             if (system_attrs & mask)
+                 continue;
+             system_attrs |= mask;
+
+             if (exprType((Node *) tle->expr) != attr->atttypid)
+             {
+                 tle->expr =
+                     (Expr *) coerce_to_target_type(pstate,
+                                                    (Node *) tle->expr,
+                                                    exprType((Node *) tle->expr),
+                                                    attr->atttypid,
+                                                    attr->atttypmod,
+                                                    COERCION_IMPLICIT,
+                                                    COERCE_IMPLICIT_CAST,
+                                                    -1);
+             }
+             tle->resjunk = true;
+         }
+     }
+ }

  /*
   * transformSelectStmt -
*************** transformSelectStmt(ParseState *pstate,
*** 869,874 ****
--- 912,918 ----
      if (stmt->intoClause)
      {
          qry->intoClause = stmt->intoClause;
+         transformSelectIntoSystemColumn(pstate, qry);
          if (stmt->intoClause->colNames)
              applyColumnNames(qry->targetList, stmt->intoClause->colNames);
      }
diff -Nrpc base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y
*** base/src/backend/parser/gram.y    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/parser/gram.y    Fri Jan 23 10:55:35 2009
***************
*** 57,62 ****
--- 57,63 ----
  #include "nodes/makefuncs.h"
  #include "nodes/nodeFuncs.h"
  #include "parser/gramparse.h"
+ #include "security/pgace.h"
  #include "storage/lmgr.h"
  #include "utils/date.h"
  #include "utils/datetime.h"
*************** static TypeName *TableFuncTypeName(List
*** 402,407 ****
--- 403,410 ----
  %type <str>        OptTableSpace OptConsTableSpace OptTableSpaceOwner
  %type <list>    opt_check_option

+ %type <defelt> OptSecurityItem SecurityItem
+
  %type <target>    xml_attribute_el
  %type <list>    xml_attribute_list xml_attributes
  %type <node>    xml_root_version opt_xml_root_standalone
*************** alter_table_cmd:
*** 1796,1801 ****
--- 1799,1822 ----
                      n->def = (Node *)$2;
                      $$ = (Node *)n;
                  }
+             /* ALTER TABLE <relation> CONTEXT = '...' */
+             | SecurityItem
+                 {
+                     AlterTableCmd *n = makeNode(AlterTableCmd);
+                     n->subtype = AT_SetSecurityLabel;
+                     n->name = NULL;
+                     n->def = (Node *) $1;
+                     $$ = (Node *) n;
+                 }
+             /* ALTER TABLE <relation> ALTER [COLUMN] <colname> CONTEXT = '...' */
+             | ALTER opt_column ColId SecurityItem
+                 {
+                     AlterTableCmd *n = makeNode(AlterTableCmd);
+                     n->subtype = AT_SetSecurityLabel;
+                     n->name = $3;
+                     n->def = (Node *) $4;
+                     $$ = (Node *) n;
+                 }
          ;

  alter_column_default:
*************** opt_using:
*** 1997,2003 ****
   *****************************************************************************/

  CreateStmt:    CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
!             OptInherit OptWith OnCommitOption OptTableSpace
                  {
                      CreateStmt *n = makeNode(CreateStmt);
                      $4->istemp = $2;
--- 2018,2024 ----
   *****************************************************************************/

  CreateStmt:    CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
!             OptInherit OptWith OnCommitOption OptTableSpace OptSecurityItem
                  {
                      CreateStmt *n = makeNode(CreateStmt);
                      $4->istemp = $2;
*************** CreateStmt:    CREATE OptTemp TABLE qualifi
*** 2008,2017 ****
                      n->options = $9;
                      n->oncommit = $10;
                      n->tablespacename = $11;
                      $$ = (Node *)n;
                  }
          | CREATE OptTemp TABLE qualified_name OF qualified_name
!             '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
                  {
                      /* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
                       * by our inheritance capabilities. Let's try it...
--- 2029,2039 ----
                      n->options = $9;
                      n->oncommit = $10;
                      n->tablespacename = $11;
+                     n->pgaceItem = (Node *) $12;
                      $$ = (Node *)n;
                  }
          | CREATE OptTemp TABLE qualified_name OF qualified_name
!             '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptSecurityItem
                  {
                      /* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
                       * by our inheritance capabilities. Let's try it...
*************** CreateStmt:    CREATE OptTemp TABLE qualifi
*** 2025,2030 ****
--- 2047,2053 ----
                      n->options = $10;
                      n->oncommit = $11;
                      n->tablespacename = $12;
+                     n->pgaceItem = (Node *) $13;
                      $$ = (Node *)n;
                  }
          ;
*************** TableElement:
*** 2067,2079 ****
              | TableConstraint                    { $$ = $1; }
          ;

! columnDef:    ColId Typename ColQualList
                  {
                      ColumnDef *n = makeNode(ColumnDef);
                      n->colname = $1;
                      n->typename = $2;
                      n->constraints = $3;
                      n->is_local = true;
                      $$ = (Node *)n;
                  }
          ;
--- 2090,2103 ----
              | TableConstraint                    { $$ = $1; }
          ;

! columnDef:    ColId Typename ColQualList OptSecurityItem
                  {
                      ColumnDef *n = makeNode(ColumnDef);
                      n->colname = $1;
                      n->typename = $2;
                      n->constraints = $3;
                      n->is_local = true;
+                     n->pgaceItem = (Node *) $4;
                      $$ = (Node *)n;
                  }
          ;
*************** common_func_opt_item:
*** 4834,4839 ****
--- 4858,4867 ----
                      /* we abuse the normal content of a DefElem here */
                      $$ = makeDefElem("set", (Node *)$1);
                  }
+             | SecurityItem
+                 {
+                     $$ = $1;
+                 }
          ;

  createfunc_opt_item:
*************** createdb_opt_item:
*** 5997,6002 ****
--- 6025,6034 ----
                  {
                      $$ = makeDefElem("owner", NULL);
                  }
+             | SecurityItem
+                 {
+                     $$ = $1;
+                 }
          ;

  /*
*************** alterdb_opt_item:
*** 6053,6058 ****
--- 6085,6094 ----
                  {
                      $$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
                  }
+             | SecurityItem
+                 {
+                     $$ = $1;
+                 }
          ;


*************** target_el:    a_expr AS ColLabel
*** 9840,9845 ****
--- 9876,9903 ----
                  }
          ;

+ /*****************************************************************************
+  *
+  * PGACE Security Items
+  *
+  *****************************************************************************/
+
+ OptSecurityItem:
+             SecurityItem                { $$ = $1; }
+             | /* EMPTY */                { $$ = NULL; }
+             ;
+
+ SecurityItem:
+             IDENT '=' Sconst
+                 {
+                     DefElem *node = makeDefElem($1, (Node *) makeString($3));
+
+                     if (!pgaceIsGramSecurityItem(node))
+                         yyerror("syntax error");
+
+                     $$ = node;
+                 }
+             ;

  /*****************************************************************************
   *
diff -Nrpc base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/parse_target.c
*** base/src/backend/parser/parse_target.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/parser/parse_target.c    Fri Jan 23 10:55:35 2009
***************
*** 14,19 ****
--- 14,20 ----
   */
  #include "postgres.h"

+ #include "catalog/heap.h"
  #include "catalog/pg_type.h"
  #include "commands/dbcommands.h"
  #include "funcapi.h"
***************
*** 27,32 ****
--- 28,34 ----
  #include "parser/parse_relation.h"
  #include "parser/parse_target.h"
  #include "parser/parse_type.h"
+ #include "security/pgace.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "utils/typcache.h"
*************** transformAssignedExpr(ParseState *pstate
*** 361,376 ****
      Oid            attrtype;        /* type of target column */
      int32        attrtypmod;
      Relation    rd = pstate->p_target_relation;

      Assert(rd != NULL);
!     if (attrno <= 0)
!         ereport(ERROR,
!                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
!                  errmsg("cannot assign to system column \"%s\"",
!                         colname),
!                  parser_errposition(pstate, location)));
!     attrtype = attnumTypeId(rd, attrno);
!     attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;

      /*
       * If the expression is a DEFAULT placeholder, insert the attribute's
--- 363,395 ----
      Oid            attrtype;        /* type of target column */
      int32        attrtypmod;
      Relation    rd = pstate->p_target_relation;
+     bool        relhasoids = RelationGetForm(rd)->relhasoids;

      Assert(rd != NULL);
!     if (attrno > 0)
!     {
!         attrtype = attnumTypeId(rd, attrno);
!         attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
!     }
!     else
!     {
!         Form_pg_attribute attr
!             = SystemAttributeDefinition(attrno, relhasoids);
!         if (attr && SystemAttributeIsWritable(attrno))
!         {
!             attrtype = attr->atttypid;
!             attrtypmod = attr->atttypmod;
!         }
!         else
!         {
!             ereport(ERROR,
!                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
!                      errmsg("cannot assign to system column \"%s\"",
!                             colname),
!                      parser_errposition(pstate, location)));
!             return NULL;    /* compiler kindness */
!         }
!     }

      /*
       * If the expression is a DEFAULT placeholder, insert the attribute's
*************** updateTargetListEntry(ParseState *pstate
*** 515,520 ****
--- 534,542 ----
       */
      tle->resno = (AttrNumber) attrno;
      tle->resname = colname;
+
+     if (SystemAttributeIsWritable(attrno))
+         tle->resjunk = true;
  }


*************** checkInsertTargets(ParseState *pstate, L
*** 789,794 ****
--- 811,817 ----
          Bitmapset  *wholecols = NULL;
          Bitmapset  *partialcols = NULL;
          ListCell   *tl;
+         uint32        system_attrs = 0;

          foreach(tl, cols)
          {
*************** checkInsertTargets(ParseState *pstate, L
*** 797,810 ****
              int            attrno;

              /* Lookup column name, ereport on failure */
!             attrno = attnameAttNum(pstate->p_target_relation, name, false);
              if (attrno == InvalidAttrNumber)
                  ereport(ERROR,
                          (errcode(ERRCODE_UNDEFINED_COLUMN),
                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                             name,
                           RelationGetRelationName(pstate->p_target_relation)),
                           parser_errposition(pstate, col->location)));

              /*
               * Check for duplicates, but only of whole columns --- we allow
--- 820,856 ----
              int            attrno;

              /* Lookup column name, ereport on failure */
!             attrno = attnameAttNum(pstate->p_target_relation, name, true);
              if (attrno == InvalidAttrNumber)
+             {
                  ereport(ERROR,
                          (errcode(ERRCODE_UNDEFINED_COLUMN),
                      errmsg("column \"%s\" of relation \"%s\" does not exist",
                             name,
                           RelationGetRelationName(pstate->p_target_relation)),
                           parser_errposition(pstate, col->location)));
+             }
+             else if (attrno < 0)
+             {
+                 if (SystemAttributeIsWritable(attrno))
+                 {
+                     uint32    mask = (1<<(-attrno));
+
+                     if ((system_attrs & mask) != 0)
+                         ereport(ERROR,
+                                 (errcode(ERRCODE_DUPLICATE_COLUMN),
+                                  errmsg("column \"%s\" specified more than once", name),
+                                  parser_errposition(pstate, col->location)));
+                     system_attrs |= mask;
+                     *attrnos = lappend_int(*attrnos, attrno);
+                     continue;
+                 }
+                 ereport(ERROR,
+                         (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+                          errmsg("column \"%s\" of relation \"%s\" is system column",
+                                 name, RelationGetRelationName(pstate->p_target_relation)),
+                                                  parser_errposition(pstate, col->location)));
+             }

              /*
               * Check for duplicates, but only of whole columns --- we allow
diff -Nrpc base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmaster/postmaster.c
*** base/src/backend/postmaster/postmaster.c    Mon Jan  5 17:36:07 2009
--- sepgsql/src/backend/postmaster/postmaster.c    Mon Jan  5 17:41:04 2009
***************
*** 108,113 ****
--- 108,114 ----
  #include "postmaster/pgarch.h"
  #include "postmaster/postmaster.h"
  #include "postmaster/syslogger.h"
+ #include "security/pgace.h"
  #include "storage/fd.h"
  #include "storage/ipc.h"
  #include "storage/pg_shmem.h"
*************** static pid_t StartupPID = 0,
*** 215,221 ****
              AutoVacPID = 0,
              PgArchPID = 0,
              PgStatPID = 0,
!             SysLoggerPID = 0;

  /* Startup/shutdown state */
  #define            NoShutdown        0
--- 216,223 ----
              AutoVacPID = 0,
              PgArchPID = 0,
              PgStatPID = 0,
!             SysLoggerPID = 0,
!             pgaceWorkerPID = 0;

  /* Startup/shutdown state */
  #define            NoShutdown        0
*************** ServerLoop(void)
*** 1330,1335 ****
--- 1332,1341 ----
          if (PgStatPID == 0 && pmState == PM_RUN)
              PgStatPID = pgstat_start();

+         /* If we have lost the pgace worker (if needed), try to start a new one */
+         if (pgaceWorkerPID == 0 && pmState == PM_RUN)
+             pgaceWorkerPID = pgaceStartupWorkerProcess();
+
          /*
           * Touch the socket and lock file every 58 minutes, to ensure that
           * they are not removed by overzealous /tmp-cleaning tasks.  We assume
*************** SIGHUP_handler(SIGNAL_ARGS)
*** 1933,1938 ****
--- 1939,1946 ----
              signal_child(SysLoggerPID, SIGHUP);
          if (PgStatPID != 0)
              signal_child(PgStatPID, SIGHUP);
+         if (pgaceWorkerPID != 0)
+             signal_child(pgaceWorkerPID, SIGHUP);

          /* Reload authentication config files too */
          if (!load_hba())
*************** pmdie(SIGNAL_ARGS)
*** 1992,1997 ****
--- 2000,2008 ----
                  /* and the walwriter too */
                  if (WalWriterPID != 0)
                      signal_child(WalWriterPID, SIGTERM);
+                 /* and the pgace worker too */
+                 if (pgaceWorkerPID != 0)
+                     signal_child(pgaceWorkerPID, SIGTERM);
                  pmState = PM_WAIT_BACKUP;
              }

*************** pmdie(SIGNAL_ARGS)
*** 2031,2036 ****
--- 2042,2050 ----
                  /* and the walwriter too */
                  if (WalWriterPID != 0)
                      signal_child(WalWriterPID, SIGTERM);
+                 /* and the pgaceWorker too */
+                 if (pgaceWorkerPID != 0)
+                     signal_child(pgaceWorkerPID, SIGTERM);
                  pmState = PM_WAIT_BACKENDS;
              }

*************** pmdie(SIGNAL_ARGS)
*** 2064,2069 ****
--- 2078,2085 ----
                  signal_child(PgArchPID, SIGQUIT);
              if (PgStatPID != 0)
                  signal_child(PgStatPID, SIGQUIT);
+             if (pgaceWorkerPID != 0)
+                 signal_child(pgaceWorkerPID, SIGQUIT);
              ExitPostmaster(0);
              break;
      }
*************** reaper(SIGNAL_ARGS)
*** 2312,2317 ****
--- 2328,2343 ----
              continue;
          }

+         /* Was it the PGACE worker process? */
+         if (pid == pgaceWorkerPID)
+         {
+             pgaceWorkerPID = 0;
+             if (!EXIT_STATUS_0(exitstatus))
+                 LogChildExit(LOG, _("PGACE worker process"),
+                              pid, exitstatus);
+             continue;
+         }
+
          /*
           * Else do standard backend child cleanup.
           */
*************** HandleChildCrash(int pid, int exitstatus
*** 2479,2484 ****
--- 2505,2522 ----
          signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
      }

+     /* Take care of the pgace worker too */
+     if (pid == pgaceWorkerPID)
+         pgaceWorkerPID = 0;
+     else if (pgaceWorkerPID != 0 && !FatalError)
+     {
+         ereport(DEBUG2,
+                 (errmsg_internal("sending %s to process %d",
+                                  (SendStop ? "SIGSTOP" : "SIGQUIT"),
+                                  (int) pgaceWorkerPID)));
+         signal_child(pgaceWorkerPID, (SendStop ? SIGSTOP : SIGQUIT));
+     }
+
      /*
       * Force a power-cycle of the pgarch process too.  (This isn't absolutely
       * necessary, but it seems like a good idea for robustness, and it
*************** PostmasterStateMachine(void)
*** 2609,2615 ****
              StartupPID == 0 &&
              (BgWriterPID == 0 || !FatalError) &&
              WalWriterPID == 0 &&
!             AutoVacPID == 0)
          {
              if (FatalError)
              {
--- 2647,2654 ----
              StartupPID == 0 &&
              (BgWriterPID == 0 || !FatalError) &&
              WalWriterPID == 0 &&
!             AutoVacPID == 0 &&
!             pgaceWorkerPID == 0)
          {
              if (FatalError)
              {
diff -Nrpc base/src/backend/rewrite/rewriteHandler.c sepgsql/src/backend/rewrite/rewriteHandler.c
*** base/src/backend/rewrite/rewriteHandler.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/rewrite/rewriteHandler.c    Fri Jan 23 10:55:35 2009
***************
*** 23,28 ****
--- 23,29 ----
  #include "rewrite/rewriteDefine.h"
  #include "rewrite/rewriteHandler.h"
  #include "rewrite/rewriteManip.h"
+ #include "security/pgace.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "commands/trigger.h"
*************** QueryRewrite(Query *parsetree)
*** 1972,1976 ****
      if (!foundOriginalQuery && lastInstead != NULL)
          lastInstead->canSetTag = true;

!     return results;
  }
--- 1973,1977 ----
      if (!foundOriginalQuery && lastInstead != NULL)
          lastInstead->canSetTag = true;

!     return pgacePostQueryRewrite(results);
  }
diff -Nrpc base/src/backend/security/Makefile sepgsql/src/backend/security/Makefile
*** base/src/backend/security/Makefile    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/Makefile    Wed Jan 14 15:02:53 2009
***************
*** 0 ****
--- 1,23 ----
+ #
+ # src/backend/security/Makefile
+ #   Makefile for Security Purpose Extensions
+ #
+ # Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ #
+ subdir = src/backend/security
+ top_builddir = ../../..
+ include $(top_builddir)/src/Makefile.global
+
+ # common facilities for enhanced security features
+ OBJS := pgaceCommon.o pgaceHooks.o
+
+ # DAC feature : Row-level Database ACLs
+ OBJS += rowacl/rowacl.o
+
+ # MAC feature : Security-Enhanced PostgreSQL
+ ifeq ($(enable_selinux), yes)
+ OBJS += sepgsql/avc.o sepgsql/core.o sepgsql/hooks.o    \
+     sepgsql/permissions.o sepgsql/proxy.o
+ endif
+
+ include $(top_builddir)/src/backend/common.mk
diff -Nrpc base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security/pgaceCommon.c
*** base/src/backend/security/pgaceCommon.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/pgaceCommon.c    Mon Dec 29 18:34:29 2008
***************
*** 0 ****
--- 1,729 ----
+
+ /*
+  * src/backend/security/pgaceCommon.c
+  *      common framework of security modules
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  */
+ #include "postgres.h"
+
+ #include "access/genam.h"
+ #include "access/hash.h"
+ #include "access/heapam.h"
+ #include "access/xact.h"
+ #include "catalog/catalog.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_attribute.h"
+ #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_security.h"
+ #include "catalog/pg_type.h"
+ #include "executor/executor.h"
+ #include "libpq/be-fsstubs.h"
+ #include "miscadmin.h"
+ #include "nodes/makefuncs.h"
+ #include "nodes/parsenodes.h"
+ #include "parser/parse_expr.h"
+ #include "security/pgace.h"
+ #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+ #include <unistd.h>
+ #include <sys/file.h>
+
+ /*****************************************************************************
+  *     GUC Parameter Support
+  *****************************************************************************/
+
+ int pgace_feature;
+
+ /*****************************************************************************
+  *     Extended SQL statements support
+  *****************************************************************************/
+
+ /*
+  * PGACE enables to create a new table labed as explicitly specified security
+  * attribute. It is implemented as an extension of SQL statement like:
+  *   CREATE TABLE memo (
+  *       id   integer primary key,
+  *       msg  TEXT
+  *   ) CONTEXT = 'system_u:object_r:sepgsql_secret_table_t';
+  *
+  * The specified security attribute is chained as a list of DefElem object,
+  * at CreateStmt->pgaceItem for a table, ColumnDef->pgaceItem for a column.
+  *
+  * These items are generated at pgaceGramSecurityItem() hook invoked from
+  * parser/gram.y. Then, pgaceRelationAttrList() pick them up and re-organize
+  * as a list, to pass it as an argument of heap_create_with_catalog().
+  *
+  * When the list is not NIL, it means user specifies a security attribute
+  * explicitly for a newly created table or column.
+  * pgaceGramCreateRelation() and pgaceGramCreateAttribute() are invoked
+  * just before inserting a new tuple into system catalog, and PGACE
+  * framework invokes pgaceGramCreateRelation() and/or pgaceGramCreateAttribute()
+  * hooks to give a chance the gurst to attach proper security attributes.
+  */
+
+ List *
+ pgaceRelationAttrList(CreateStmt *stmt)
+ {
+     List       *result = NIL;
+     ListCell   *l;
+     DefElem    *defel, *newel;
+
+     if (stmt->pgaceItem)
+     {
+         defel = (DefElem *) stmt->pgaceItem;
+
+         Assert(IsA(defel, DefElem));
+
+         if (!pgaceIsGramSecurityItem(defel))
+             elog(ERROR, "node is not a pgace security item");
+         newel = makeDefElem(NULL, (Node *) copyObject(defel));
+         result = lappend(result, newel);
+     }
+
+     foreach(l, stmt->tableElts)
+     {
+         ColumnDef  *cdef = (ColumnDef *) lfirst(l);
+
+         defel = (DefElem *) cdef->pgaceItem;
+
+         if (defel)
+         {
+             Assert(IsA(defel, DefElem));
+
+             if (!pgaceIsGramSecurityItem(defel))
+                 elog(ERROR, "node is not a pgace security item");
+             newel = makeDefElem(pstrdup(cdef->colname),
+                                 (Node *) copyObject(defel));
+             result = lappend(result, newel);
+         }
+     }
+     return result;
+ }
+
+ void
+ pgaceCreateRelationCommon(Relation rel, HeapTuple tuple, List *pgaceAttrList)
+ {
+     ListCell   *l;
+
+     foreach(l, pgaceAttrList)
+     {
+         DefElem    *defel = (DefElem *) lfirst(l);
+
+         if (!defel->defname)
+         {
+             Assert(pgaceIsGramSecurityItem((DefElem *) defel->arg));
+             pgaceGramCreateRelation(rel, tuple, (DefElem *) defel->arg);
+             break;
+         }
+     }
+ }
+
+ void
+ pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple,
+                            List *pgaceAttrList)
+ {
+     Form_pg_attribute attr = (Form_pg_attribute) GETSTRUCT(tuple);
+     ListCell   *l;
+
+     foreach(l, pgaceAttrList)
+     {
+         DefElem    *defel = lfirst(l);
+
+         if (!defel->defname)
+             continue;            /* for table */
+         if (strcmp(defel->defname, NameStr(attr->attname)) == 0)
+         {
+             Assert(pgaceIsGramSecurityItem((DefElem *) defel->arg));
+             pgaceGramCreateAttribute(rel, tuple, (DefElem *) defel->arg);
+             break;
+         }
+     }
+ }
+
+ /*
+  * pgaceAlterRelationCommon()
+  *
+  * This function is invoked when a user requires to change security attribute
+  * of table/column with "ALTER TABLE" statement.
+  *
+  * When a user attempt to relabel a table, PGACE invokes alterRelationCommon()
+  * and it gives the guest module a chance to set a new security attribute of
+  * specified table.
+  * When a user attempt to relabel a column, PGACE invokes alterAttributeCommon()
+  * and it gives the guest module a chance to set a new security attribute of
+  * specified column.
+  */
+
+ static void
+ alterRelationCommon(Relation rel, DefElem *defel)
+ {
+     Relation    pg_class;
+     HeapTuple    tuple;
+
+     pg_class = heap_open(RelationRelationId, RowExclusiveLock);
+
+     tuple = SearchSysCacheCopy(RELOID,
+                                ObjectIdGetDatum(RelationGetRelid(rel)),
+                                0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "cache lookup failed for relation '%s'",
+              RelationGetRelationName(rel));
+     pgaceGramAlterRelation(rel, tuple, defel);
+
+     simple_heap_update(pg_class, &tuple->t_self, tuple);
+     CatalogUpdateIndexes(pg_class, tuple);
+
+     heap_freetuple(tuple);
+     heap_close(pg_class, RowExclusiveLock);
+ }
+
+ static void
+ alterAttributeCommon(Relation rel, char *colName, DefElem *defel)
+ {
+     Relation    pg_attr;
+     HeapTuple    tuple;
+
+     pg_attr = heap_open(AttributeRelationId, RowExclusiveLock);
+
+     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "cache lookup failed for attribute '%s' of relation '%s'",
+              colName, RelationGetRelationName(rel));
+     pgaceGramAlterAttribute(rel, tuple, defel);
+
+     simple_heap_update(pg_attr, &tuple->t_self, tuple);
+     CatalogUpdateIndexes(pg_attr, tuple);
+
+     heap_freetuple(tuple);
+     heap_close(pg_attr, RowExclusiveLock);
+ }
+
+ void
+ pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd)
+ {
+     DefElem    *defel = (DefElem *) cmd->def;
+
+     Assert(IsA(defel, DefElem));
+
+     if (!pgaceIsGramSecurityItem(defel))
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("PGACE: unsupported security item")));
+
+     if (!cmd->name)
+     {
+         alterRelationCommon(rel, defel);
+     }
+     else
+     {
+         alterAttributeCommon(rel, cmd->name, defel);
+     }
+ }
+
+ /*****************************************************************************
+  *    security attribute management
+  *****************************************************************************/
+
+ /*
+  * The following functions enables to manage security attribute of each tuple
+  * (including ones within system catalog).
+  *
+  * Security attribute has these features:
+  * 1. It is imported/exported with text representation, like
+  *    'system_u:object_r:sepgsql_table_t:s0'
+  * 2. In generally, many tuples share a same security attribute.
+  *    (They are grouped by security attribute in other word.)
+  * 3. A object can have one security attribute at most.
+  *    (It can have a state of unlabeled.)
+  *
+  * PGACE utilizes a newly added system catalog of pg_security to store text
+  * representation of security attribute efficiently. Any tuple has a object id
+  * of a tuple within pg_security system catalog, we call it as a security id.
+  *
+  * Users can show security attribute as if it stored text data, but any tuple
+  * has a security id which has a length of sizeof(Oid), without text data.
+  * It is translated each other when it is exported/imported.
+  *
+  * pgaceSidToSecurityLabel() returns a text representation for a given security,
+  * id, and pgaceSecurityLabelToSid() returns a security id for a give text
+  * representation. (If a given text representation was not found on pg_security
+  * system catalog, PGACE inserts a new entry automatically.)
+  *
+  * In the very early phase (invoked by initdb), pg_security system catalos is
+  * not available yet. The earlySecurityLabelToSid() and earlySidToSecurityLabel()
+  * is used to hold relationships between security id and text representation.
+  * These relationships are stored at the end of bootstraping mode by
+  * pgacePostBootstrapingMode(). It write any cached relationships into pg_security
+  * system catalog.
+  */
+
+ typedef struct earlySeclabel
+ {
+     struct earlySeclabel *next;
+     Oid            sid;
+     char        label[1];
+ } earlySeclabel;
+
+ static earlySeclabel *earlySeclabelList = NULL;
+
+ static Oid
+ earlySecurityLabelToSid(char *label)
+ {
+     earlySeclabel *es;
+     Oid            minsid = SecurityRelationId;
+
+     for (es = earlySeclabelList; es != NULL; es = es->next)
+     {
+         if (!strcmp(label, es->label))
+             return es->sid;
+         if (es->sid < minsid)
+             minsid = es->sid;
+     }
+     /*
+      * not found
+      */
+     es = malloc(sizeof(earlySeclabel) + strlen(label));
+     es->next = earlySeclabelList;
+     es->sid = minsid - 1;
+     strcpy(es->label, label);
+     earlySeclabelList = es;
+
+     return es->sid;
+ }
+
+ static char *
+ earlySidToSecurityLabel(Oid sid)
+ {
+     earlySeclabel *es;
+
+     for (es = earlySeclabelList; es != NULL; es = es->next)
+     {
+         if (es->sid == sid)
+             return pstrdup(es->label);
+     }
+
+     return NULL;    /* not found */
+ }
+
+ void
+ pgacePostBootstrapingMode(void)
+ {
+     Relation    rel;
+     CatalogIndexState ind;
+     HeapTuple    tuple;
+     earlySeclabel *es, *_es;
+     Oid            meta_sid;
+     Datum        value;
+     bool        isnull;
+
+     if (!earlySeclabelList)
+         return;
+
+     StartTransactionCommand();
+
+     meta_sid = earlySecurityLabelToSid(pgaceSecurityLabelOfLabel());
+
+     rel = heap_open(SecurityRelationId, RowExclusiveLock);
+     ind = CatalogOpenIndexes(rel);
+
+     for (es = earlySeclabelList; es != NULL; es = _es)
+     {
+         _es = es->next;
+
+         value = DirectFunctionCall1(textin, CStringGetDatum(es->label));
+         isnull = false;
+         tuple = heap_form_tuple(RelationGetDescr(rel), &value, &isnull);
+
+         HeapTupleSetOid(tuple, es->sid);
+         if (HeapTupleHasSecLabel(tuple))
+             HeapTupleSetSecLabel(tuple, meta_sid);
+
+         simple_heap_insert(rel, tuple);
+         CatalogIndexInsert(ind, tuple);
+
+         heap_freetuple(tuple);
+
+         free(es);
+     }
+     CatalogCloseIndexes(ind);
+     heap_close(rel, RowExclusiveLock);
+
+     CommitTransactionCommand();
+ }
+
+ /*
+  * pgaceLookupSecurityId()
+  *
+  * The PGACE guest subsystem can use this interface to get a security id
+  * for a given text representation.
+  */
+ Oid
+ pgaceLookupSecurityId(char *raw_label)
+ {
+     Oid            labelOid, labelSid;
+     HeapTuple    tuple;
+
+     if (IsBootstrapProcessingMode())
+         return earlySecurityLabelToSid(raw_label);
+
+     /*
+      * lookup syscache at first
+      */
+     tuple = SearchSysCache(SECURITYLABEL,
+                            CStringGetTextDatum(raw_label),
+                            0, 0, 0);
+     if (HeapTupleIsValid(tuple))
+     {
+         labelOid = HeapTupleGetOid(tuple);
+         ReleaseSysCache(tuple);
+     }
+     else
+     {
+         /*
+          * not found, insert a new one into pg_security
+          */
+         Relation    rel;
+         CatalogIndexState ind;
+         char       *slabel;
+         Datum        labelTxt;
+         bool        isnull;
+
+         rel = heap_open(SecurityRelationId, RowExclusiveLock);
+
+         slabel = pgaceSecurityLabelOfLabel();
+
+         if (!slabel)
+         {
+             labelSid = InvalidOid;
+             labelOid = GetNewOid(rel);
+         }
+         else if (!strcmp(raw_label, slabel))
+         {
+             labelOid = labelSid = GetNewOid(rel);
+         }
+         else
+         {
+             labelSid = pgaceLookupSecurityId(slabel);
+             labelOid = GetNewOid(rel);
+         }
+
+         ind = CatalogOpenIndexes(rel);
+
+         labelTxt = CStringGetTextDatum(raw_label);
+         isnull = false;
+         tuple = heap_form_tuple(RelationGetDescr(rel),
+                                 &labelTxt, &isnull);
+         if (HeapTupleHasSecLabel(tuple))
+             HeapTupleSetSecLabel(tuple, labelSid);
+         HeapTupleSetOid(tuple, labelOid);
+
+         simple_heap_insert(rel, tuple);
+         CatalogIndexInsert(ind, tuple);
+
+         /*
+          * NOTE:
+          * We also have to insert a cache entry of new tuple of
+          * pg_security for temporary usage.
+          * If user tries to apply same security attribute twice
+          * or more within same command id, PGACE cannot decide
+          * whether it should be inserted, or not, because it
+          * cannot scan the prior one with SnapshotNow.
+          *
+          * A cache entry inserted will be invalidated on the
+          * next CommandIdIncrement().
+          * The purpose of InsertSysCache() here is to prevent
+          * duplicate insertion
+          */
+         InsertSysCache(RelationGetRelid(rel), tuple);
+
+         CatalogCloseIndexes(ind);
+         heap_close(rel, RowExclusiveLock);
+     }
+
+     return labelOid;
+ }
+
+ Oid
+ pgaceSecurityLabelToSid(char *label)
+ {
+     char *raw_label = pgaceTranslateSecurityLabelIn(label);
+
+     if (!pgaceCheckValidSecurityLabel(raw_label))
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("PGACE: invalid security label: %s", raw_label)));
+
+     return pgaceLookupSecurityId(raw_label);
+ }
+
+ /*
+  * pgaceLookupSecurityLabel()
+  *
+  * The PGACE guest module can use this interface to get a text representation
+  * in raw-format, without cosmetic translation.
+  */
+ char *
+ pgaceLookupSecurityLabel(Oid sid)
+ {
+     HeapTuple    tuple;
+     Datum        labelTxt;
+     char       *label;
+     bool        isnull;
+
+     if (!OidIsValid(sid))
+         return NULL;
+
+     if (IsBootstrapProcessingMode())
+         return earlySidToSecurityLabel(sid);
+
+     tuple = SearchSysCache(SECURITYOID,
+                            ObjectIdGetDatum(sid),
+                            0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         return NULL;
+
+     labelTxt = SysCacheGetAttr(SECURITYOID,
+                                tuple, Anum_pg_security_seclabel, &isnull);
+     Assert(!isnull);
+     label = TextDatumGetCString(labelTxt);
+     ReleaseSysCache(tuple);
+
+     return label;
+ }
+
+ char *
+ pgaceSidToSecurityLabel(Oid sid)
+ {
+     char *label;
+
+     label = pgaceLookupSecurityLabel(sid);
+     if (!label || !pgaceCheckValidSecurityLabel(label))
+         label = pgaceUnlabeledSecurityLabel();
+
+     if (!label)
+         return pstrdup("");
+
+     return pgaceTranslateSecurityLabelOut(label);
+ }
+
+ Datum
+ pgaceHeapGetSecurityLabelSysattr(HeapTuple tuple)
+ {
+     Oid sid = HeapTupleGetSecLabel(tuple);
+
+     return CStringGetTextDatum(pgaceSidToSecurityLabel(sid));
+ }
+
+ /*****************************************************************************
+  *     Set/Get security attribute of Large Object
+  *****************************************************************************/
+
+ /*
+  * lo_get_security()
+  *
+  * This function returns a security attribute of large object
+  * in TEXT representation.
+  *
+  * It assumes the first page means the whole of large object.
+  * The guest of PGACE should pay effort to keep its consistency.
+  */
+ Datum
+ lo_get_security(PG_FUNCTION_ARGS)
+ {
+     Oid            loid = PG_GETARG_OID(0);
+     Relation    rel;
+     ScanKeyData skey;
+     SysScanDesc scan;
+     HeapTuple    tuple;
+     Oid            sid;
+
+     rel = heap_open(LargeObjectRelationId, AccessShareLock);
+
+     ScanKeyInit(&skey,
+                 Anum_pg_largeobject_loid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(loid));
+
+     scan = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
+                               SnapshotNow, 1, &skey);
+     tuple = systable_getnext(scan);
+     if (!HeapTupleIsValid(tuple))
+         ereport(ERROR,
+                 (errcode(ERRCODE_UNDEFINED_OBJECT),
+                  errmsg("large object %u does not exist", loid)));
+     pgaceLargeObjectGetSecurity(rel, tuple);
+     sid = HeapTupleGetSecLabel(tuple);
+
+     systable_endscan(scan);
+     heap_close(rel, AccessShareLock);
+
+     return CStringGetTextDatum(pgaceSidToSecurityLabel(sid));
+ }
+
+ /*
+  * lo_set_security()
+  *
+  * This function set a new security attribute of a large object.
+  * It scans pg_largeobject system catalog with a given loid,
+  * and invokes pgaceLargeObjectSetSecurity() for each page frame.
+  */
+ Datum
+ lo_set_security(PG_FUNCTION_ARGS)
+ {
+     Oid            loid = PG_GETARG_OID(0);
+     Datum        labelTxt = PG_GETARG_DATUM(1);
+     Relation    rel;
+     ScanKeyData skey;
+     SysScanDesc sd;
+     HeapTuple    oldtup, newtup;
+     CatalogIndexState indstate;
+     Oid            sid;
+     List       *okList = NIL;
+     bool        found = false;
+
+     sid = pgaceSecurityLabelToSid(TextDatumGetCString(labelTxt));
+
+     ScanKeyInit(&skey,
+                 Anum_pg_largeobject_loid,
+                 BTEqualStrategyNumber,
+                 F_OIDEQ, ObjectIdGetDatum(loid));
+
+     rel = heap_open(LargeObjectRelationId, RowExclusiveLock);
+
+     indstate = CatalogOpenIndexes(rel);
+
+     sd = systable_beginscan(rel,
+                             LargeObjectLOidPNIndexId, true,
+                             SnapshotNow, 1, &skey);
+
+     while ((oldtup = systable_getnext(sd)) != NULL)
+     {
+         ListCell *l;
+
+         newtup = heap_copytuple(oldtup);
+         HeapTupleSetSecLabel(newtup, sid);
+
+         foreach (l, okList)
+         {
+             if (HeapTupleGetSecLabel(oldtup) == lfirst_oid(l))
+                 goto skip;        /* already checked */
+         }
+         okList = lappend_oid(okList, HeapTupleGetSecLabel(oldtup));
+
+         pgaceLargeObjectSetSecurity(rel, newtup, oldtup);
+     skip:
+         simple_heap_update(rel, &newtup->t_self, newtup);
+         CatalogUpdateIndexes(rel, newtup);
+         found = true;
+     }
+     systable_endscan(sd);
+     CatalogCloseIndexes(indstate);
+     heap_close(rel, RowExclusiveLock);
+
+     CommandCounterIncrement();
+
+     if (!found)
+         ereport(ERROR,
+                 (errcode(ERRCODE_UNDEFINED_OBJECT),
+                  errmsg("large object %u does not exist", loid)));
+
+     PG_RETURN_BOOL(true);
+ }
+
+ /******************************************************************
+  * Function stubs related to security modules
+  ******************************************************************/
+
+ /*
+  * If the guest of PGACE added its specific functions, it has to put
+  * function stubs on the following section, because the guest modules
+  * are not compiled and linked when it is disabled.
+  * It can cause a build problem in other environments.
+  */
+ #ifndef HAVE_SELINUX
+
+ static Datum
+ unavailable_function(const char *fn_name, int error_code)
+ {
+     ereport(ERROR,
+             (errcode(error_code),
+              errmsg("%s is not available", fn_name)));
+     PG_RETURN_VOID();
+ }
+
+ Datum
+ sepgsql_getcon(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_getservcon(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_get_user(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_get_role(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_get_type(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_get_range(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_set_user(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_set_role(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_set_type(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ Datum
+ sepgsql_set_range(PG_FUNCTION_ARGS)
+ {
+     return unavailable_function(__FUNCTION__,
+                                 ERRCODE_SELINUX_ERROR);
+ }
+
+ #endif   /* HAVE_SELINUX */
diff -Nrpc base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/pgaceHooks.c
*** base/src/backend/security/pgaceHooks.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/pgaceHooks.c    Wed Jan 21 17:22:37 2009
***************
*** 0 ****
--- 1,1547 ----
+ /*
+  * src/backend/security/pgaceHooks.c
+  *    Security hooks in PostgreSQL Access Control Extension (PGACE)
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  */
+ #include "postgres.h"
+
+ #include "security/pgace.h"
+
+ /*
+  * GUC parameter: pgace_feature
+  * It allows users to choose an enhanced security feature.
+  * It has a state of 'none' in the default, so you should
+  * specify it explicitly with initdb --pgace-feature=FEATURE.
+  */
+ int pgace_feature;
+
+ /*
+  * PGACE (PostgreSQL Access Control Extension)
+  *
+  * It provides a set of security hooks at strategic points and
+  * common facilities to manage security attribute of database
+  * objects. Its purpose is to allow various kind of enhanced
+  * security features with minimum impact to the core PostgreSQL
+  * codes.
+  * In generally, individual security feature has its own access
+  * control model, policy and granuality, however, they also have
+  * facilities to be shared commonly.
+  *
+  * The one is a set of security hooks. All the enhanced security
+  * codes have to be invoked via the hooks, and return a proper
+  * value or raise an error, if necessary.
+  * When you add a new security feature, you need the following steps.
+  *   1. add a option to 'pgace_feature' parameter.
+  *   2. modify hooks to invoke your security feature.
+  *      Please note that you don't need to modify all the hooks.
+  *      If you don't provide any feature, please keep it as is.
+  *
+  * Example: pgaceHeapTupleInsert() hook
+  * ------------------------------------
+  * bool
+  * pgaceHeapTupleInsert(Relation rel, HeapTuple tuple,
+  *                      bool is_internal, bool with_returning)
+  * {
+  *     if (!rowaclHeapTupleInsert(rel, tuple,
+  *                                   is_internal,
+  *                                with_returning))
+  *         return false;
+  *
+  *     switch (pgace_feature)
+  *     {
+  * #ifdef HAVE_SELINUX
+  *     case PGACE_FEATURE_SELINUX:
+  *         if (sepgsqlIsEnabled())
+  *             return sepgsqlHeapTupleInsert(rel, tuple,
+  *                                           is_internal,
+  *                                           with_returning);
+  *     break;
+  * #endif
+  * #ifdef HAVE_FOO_SECURITY
+  *     case PGACE_FEATURE_FOO_SECURITY:
+  *         return fooSecurityHeapTupleInsert(rel, tuple,
+  *                                           is_internal,
+  *                                           with_returning);
+  *     break;
+  * #endif
+  *     default:
+  *         break;
+  *     }
+  * return true;
+  * }
+  * ------------------------------------
+  * If your security feature has platform dependency, related code
+  * should be enclosed by #ifdef ... #endif block.
+  * (In this case, it is named as FOO_SECURITY.)
+  * The pgace_feature shows what enhanced security feature is activated
+  * in this system. If your security feature is chosen, it can be invoked
+  * via pgaceHeapTupleInsert() just before a new tuple is inserted on
+  * the target relation. Your fooSecurityHeapTupleInsert() can make its
+  * decision based on its policy and given informations.
+  * This hook requires to return 'true' or 'false'. If it returns 'false',
+  * it will be skipped to insert the given tuple.
+  * You can notice the Row-level database ACLs feature is hardwired.
+  * It is an application of traditional DAC policy in Row-level.
+  *
+  * The other is facilities to manage security attribtue of database
+  * objects. They have text representation as most of secure operating
+  * system doing, but it is not stored in each tuples directly, to reduce
+  * storage comsumption.
+  * We can fetch them via HeapTupleGetSecLabel(tuple) macro. It is stored
+  * as a Oid value (called as security identifier) which indicates pg_security
+  * system catalog. It holds mapping between security identifier and security
+  * attribute in text representation.
+  * User can see/set security attribute of database objects via security_label
+  * system column.
+  */
+
+ /******************************************************************
+  * Initialization hooks
+  ******************************************************************/
+
+ /*
+  * pgaceShmemSize
+  *
+  * This hook has to return the size of shared memory required
+  * by the guest. If it needs no shared memory region, it should
+  * return 0.
+  */
+ Size
+ pgaceShmemSize(void)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlShmemSize();
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     return (Size) 0;
+ }
+
+ /*
+  * pgaceInitialize
+  *
+  * This hook is invoked when a new PostgreSQL instance is created.
+  * The guest can use this hook to initialize itself.
+  *
+  * is_bootstrap is true, if bootstraping mode.
+  */
+ void
+ pgaceInitialize(bool is_bootstrap)
+ {
+     /* Hardwired DAC initialization */
+     rowaclInitialize(is_bootstrap);
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlInitialize(is_bootstrap);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceStartupWorkerProcess
+  *
+  * The guest can create a worker process in this hook, if necessary.
+  * (currently, PGACE does not support multiple worker processes.)
+  *
+  * This hooks has to return the PID of child process. It is managed
+  * by postmaster in the same way to manage the other children.
+  * So, the worker process has to be available to handle signals.
+  *
+  * If unnecessary, it has to return (pid_t) 0.
+  */
+ pid_t
+ pgaceStartupWorkerProcess(void)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlStartupWorkerProcess();
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     return (pid_t) 0;
+ }
+
+ /******************************************************************
+  * SQL proxy hooks
+  ******************************************************************/
+
+ /*
+  * pgacePostQueryRewrite
+  *
+  * This hook is invoked just after query is rewritten.
+  *
+  * The guest can check/modify/replace given query trees in this
+  * hook, if necessary.
+  * queryList is a list of Query object processes by rewriter.
+  */
+ List *
+ pgacePostQueryRewrite(List *queryList)
+ {
+     /* Hardwired DAC checks */
+     queryList = rowaclPostQueryRewrite(queryList);
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlPostQueryRewrite(queryList);
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     return queryList;
+ }
+
+ /*
+  * pgaceExecutorStart
+  *
+  * This hook is invoked on the head of ExecutorStart().
+  *
+  * The arguments of this hook are come from the ones of ExecutorStart
+  * as is.
+  */
+ void
+ pgaceExecutorStart(QueryDesc *queryDesc, int eflags)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlExecutorStart(queryDesc, eflags);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceExecScan
+  *
+  * This hook is invoked on ExecScan for each tuple fetched.
+  * The guest can check its visibility, and can skip to scan the given
+  * tuple. If this hook returns false, the tuple is filtered from the
+  * result set or the target of updates/deletion.
+  *
+  * Otherwise, it has to return true.
+  *
+  * The guest can refer Scan::pgaceTuplePerms (declared as uint32).
+  * It is a copy come from RangeTblEntry::pgaceTuplePerms set in
+  * the previous phase. It can be used to mark what permissions are
+  * required to scanned tuples.
+  */
+ bool
+ pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot)
+ {
+     /* Hardwired DAC checks */
+     if (!rowaclExecScan(scan, rel, slot))
+         return false;
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlExecScan(scan, rel, slot);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return true;
+ }
+
+ /*
+  * pgaceProcessUtility
+  *
+  * This hooks is invoked on the head of ProcessUtility().
+  */
+ void
+ pgaceProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlProcessUtility(parsetree, params, isTopLevel);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /******************************************************************
+  * HeapTuple modification hooks
+  ******************************************************************/
+
+ /*
+  * pgaceHeapTupleInsert
+  *
+  * This hooks is invoked just before a new tuple is inserted.
+  * If it returns false, inserting the given tuple is skipped.
+  * (or generates an error, if we cannot skip it simply.)
+  *
+  * The guest has to set a security attribute of a newly inserted
+  * tuple, if necessary and when user does not specify it explicitly.
+  *
+  * arguments:
+  * - rel is the target relation to be inserted.
+  * - tuple is the new tuple to be inserted.
+  * - is_internal is a bool to show whether it directly come from
+  *   user's query, or not.
+  * - with_returning is a bool to show whether this INSERT statement
+  *   has RETURNING clause, or not.
+  */
+ bool
+ pgaceHeapTupleInsert(Relation rel, HeapTuple tuple,
+                      bool is_internal, bool with_returning)
+ {
+     /* Hardwired  DAC check */
+     if (!rowaclHeapTupleInsert(rel, tuple,
+                                is_internal,
+                                with_returning))
+         return false;
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlHeapTupleInsert(rel, tuple,
+                                           is_internal,
+                                           with_returning);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return true;
+ }
+
+ /*
+  * pgaceHeapTupleUpdate
+  *
+  * This hook is invoked just before a tuple is updated.
+  * If it returns false, updating the given tuple is skipped.
+  * (or generates an error, if we cannot skip it simply.)
+  *
+  * The guest has to preserve a security attribute of the updated
+  * tuple, if necessary and when user specify its new security
+  * attribute explicitly.
+  *
+  * arguments:
+  * - rel is the target relation to be updated.
+  * - otid is the ItemPointer of the tuple with older version.
+  * - newtup is the tuple to be updated.
+  * - is_internal is a bool to show whether it directly come from
+  *   user's query, or not.
+  * - with_returning is a bool to show whether this INSERT statement
+  *   has RETURNING clause, or not.
+  */
+ bool
+ pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
+                      bool is_internal, bool with_returning)
+ {
+     /* Hardwired DAC check */
+     if (!rowaclHeapTupleUpdate(rel, otid, newtup,
+                                is_internal,
+                                with_returning))
+         return false;
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlHeapTupleUpdate(rel, otid, newtup,
+                                           is_internal,
+                                           with_returning);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return true;
+ }
+
+ /*
+  * pgaceHeapTupleDelete
+  *
+  * This hook is invoked just before a tuple is deleted.
+  * If it returns false, deleting the given tuple is skipped.
+  * (or generates an error, if we cannot skip it simply.)
+  *
+  * arguments:
+  * - rel is the target relation to be deleted.
+  * - otid is the ItemPointer of the tuple to be deleted.
+  * - is_internal is a bool to show whether it directly come from
+  *   user's query, or not.
+  * - with_returning is a bool to show whether this INSERT statement
+  *   has RETURNING clause, or not.
+  */
+ bool
+ pgaceHeapTupleDelete(Relation rel, ItemPointer otid,
+                      bool is_internal, bool with_returning)
+ {
+     /* Hardwired DAC check */
+     if (!rowaclHeapTupleDelete(rel, otid,
+                                is_internal,
+                                with_returning))
+         return false;
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlHeapTupleDelete(rel, otid,
+                                           is_internal,
+                                           with_returning);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return true;
+ }
+
+ /******************************************************************
+  * Extended SQL statement hooks
+  ******************************************************************/
+
+ /*
+  * pgaceIsGramSecurityItem
+  *
+  * PGACE framework provides its guest to manage security attribute
+  * for some kind of database obejcts, using an enhanced SQL statement.
+  *
+  * For example:
+  *   CREATE TABLE tbl (
+  *       x  integer,
+  *       y  text
+  *   ) security_label = 'system_u:object_r:sepgsql_table_t:Classified';
+  *
+  * This hook is invoked during parsing given queries at parser/gram.y.
+  * It generates a DefElem object which holds explicitly specified
+  * security attribute. If working guest support the feature and the
+  * given DefElem has correct pair of defname and argument string,
+  * this hook should return true.
+  * In ths above example, the given DefElem has "security_label" as
+  * defname, and "system_u:object_r:sepgsql_table_t:Classified" as
+  * its argument string.
+  */
+ bool
+ pgaceIsGramSecurityItem(DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlIsGramSecurityItem(defel);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return false;
+ }
+
+ /*
+  * The series of following hooks has three arguments.
+  * - rel is an opened relation of the target system catalog.
+  * - tuple is a new tuple to be inserted/updated.
+  * - defel is a DefElem object checked in pgaceIsGramSecurityItem().
+  */
+
+ /*
+  * pgaceGramCreateRelation
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before inserting a new tuple into pg_class system catalog on
+  * the processing of CREATE TABLE.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a new relation.
+  */
+ void
+ pgaceGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramCreateRelation(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of table "
+                         "via CREATE TABLE")));
+ }
+
+ /*
+  * pgaceGramCreateAttribute
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before inserting a new tuple into pg_attribute system catalog on
+  * the processing of CREATE TABLE.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a new column.
+  */
+ void
+ pgaceGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramCreateAttribute(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of column "
+                         "via CREATE TABLE")));
+ }
+
+ /*
+  * pgaceGramAlterRelation
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before updating an older tuple of pg_class system catalog on
+  * the processing of ALTER TABLE.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a table.
+  */
+ void
+ pgaceGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramAlterRelation(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of table "
+                         "via ALTER TABLE")));
+ }
+
+ /*
+  * pgaceGramAlterAttribute
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before updating an older tuple of pg_attribute system catalog on
+  * the processing of ALTER TABLE.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a column.
+  */
+ void
+ pgaceGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramAlterAttribute(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of column "
+                         "via ALTER TABLE")));
+ }
+
+ /*
+  * pgaceGramCreateDatabase
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before inserting a new tuple into pg_database system catalog on
+  * the processing of CREATE DATABASE.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a database.
+  */
+ void
+ pgaceGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramCreateDatabase(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of database "
+                         "via CREATE DATABASE")));
+ }
+
+ /*
+  * pgaceGramAlterDatabase
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before updating an older tuple of pg_database system catalog on
+  * the processing of ALTER DATABASE.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a database.
+  */
+ void
+ pgaceGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramAlterDatabase(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of database "
+                         "via ALTER DATABASE")));
+ }
+
+ /*
+  * pgaceGramCreateFunction
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before inserting a new tuple into pg_proc system catalog on
+  * the processing of CREATE FUNCTION.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a function.
+  */
+ void
+ pgaceGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramCreateFunction(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of function "
+                         "via CREATE FUNCTION")));
+ }
+
+ /*
+  * pgaceGramAlterFunction
+  *
+  * This hook invoked to apply an explicitly specified security attribute
+  * just before updating an older tuple of pg_proc system catalog on
+  * the processing of ALTER FUNCTION.
+  * The guest can attach the required security attribute for the given
+  * tuple which means a function.
+  */
+ void
+ pgaceGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlGramAlterFunction(rel, tuple, defel);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+
+     if (defel)
+         ereport(ERROR,
+                 (errcode(ERRCODE_PGACE_ERROR),
+                  errmsg("unable to set security attribute of function "
+                         "via ALTER FUNCTION")));
+ }
+
+ /******************************************************************
+  * DATABASE related hooks
+  ******************************************************************/
+
+ /*
+  * pgaceSetDatabaseParam
+  *
+  * This hook is invoked just before putting a new value on a GUC
+  * variable.
+  *
+  * arguments:
+  * - name is a name of GUC variable.
+  * - argstring is its new value. NULL means user tries to reset
+  *   the given GUC variable.
+  */
+ void
+ pgaceSetDatabaseParam(const char *name, char *argstring)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlSetDatabaseParam(name, argstring);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceGetDatabaseParam
+  *
+  * This hook is invoked just before reffering a GUC variable.
+  *
+  * arguments:
+  * - name is a name of GUC variable.
+  */
+ void
+ pgaceGetDatabaseParam(const char *name)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlGetDatabaseParam(name);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /******************************************************************
+  * FUNCTION related hooks
+  ******************************************************************/
+
+ /*
+  * pgaceCallFunction
+  *
+  * This hook is invoked when a function is invoked as a part
+  * of the given query. It provides a FmgrInfo object of the
+  * function, so the guest can store its opaque data within
+  * FmgrInfo::fn_pgaceItem.
+  */
+ void
+ pgaceCallFunction(FmgrInfo *finfo)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlCallFunction(finfo);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceCallAggFunction
+  *
+  * This hook is invoked when an aggregate function is invoked
+  * in the given query. pgaceCallFunction() is also invoked for
+  * its transate function and finalize function.
+  *
+  * arguments:
+  * - aggTuple is the tuple of target aggregate function stored
+  *   in pg_aggregate system catalog.
+  */
+ void
+ pgaceCallAggFunction(HeapTuple aggTuple)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlCallAggFunction(aggTuple);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceCallFunctionTrigger
+  *
+  * This hook is invoked just before executing trigger function.
+  * If it returns false, the trigger function is not invoked and
+  * caller receives a NULL tuple as a result.
+  * (It also means skip to update/delete the tuple in BR-triggers.)
+  */
+ bool
+ pgaceCallTriggerFunction(TriggerData *tgdata)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlCallTriggerFunction(tgdata);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return true;
+ }
+
+ /*
+  * pgaceBeginPerformCheckFK
+  *
+  * This hook is invoked just before performing FK constraint checks.
+  * The guest can change its internal state during the checks.
+  * The major purpose of this function is to prevent violation of
+  * integrity consistentency violation due to row-level access control.
+  * If the guest requires an opaque data, it should be returned then
+  * it will be delivered via pgaceEndPerformCheckFK().
+  */
+ void
+ pgaceBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid,
+                          Datum *rowacl_private, Datum *pgace_private)
+ {
+     /* A wired DAC state change */
+     *rowacl_private = rowaclBeginPerformCheckFK(rel, is_primary, save_userid);
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             *pgace_private = sepgsqlBeginPerformCheckFK(rel, is_primary, save_userid);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceEndPerformCheckFK
+  *
+  * This hook is invoked just after performing FK constraint checks.
+  * The guest can restore its internal state using this hook.
+  */
+ void
+ pgaceEndPerformCheckFK(Relation rel, Datum rowacl_private, Datum pgace_private)
+ {
+     /* A wired DAC state restore */
+     rowaclEndPerformCheckFK(rel, rowacl_private);
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlEndPerformCheckFK(rel, pgace_private);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceAllowInlineFunction
+  *
+  * This hook gives guest a chance to make decision just before
+  * a set-returning function is inlined.
+  *
+  * arguments:
+  * - fnoid is oid of the function to be inlined.
+  * - func_tuple is tuple of the function stored in pg_proc.
+  */
+ bool
+ pgaceAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlAllowFunctionInlined(fnoid, func_tuple);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return true;
+ }
+
+ /******************************************************************
+  * TABLE related hooks
+  ******************************************************************/
+
+ /*
+  * pgaceLockTable
+  *
+  * This hook is invoked when user tries to LOCK a table explicitly.
+  * The argument of relid shows the target relation id.
+  */
+ void
+ pgaceLockTable(Oid relid)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLockTable(relid);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceExecTruncate
+  *
+  * This hook is invoked just before it truncate tables.
+  * The argument is a list of already opened relations with
+  * AccessExclusiveLock.
+  */
+ void
+ pgaceExecTruncate(List *trunk_rels)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlExecTruncate(trunk_rels);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /******************************************************************
+  * COPY TO/COPY FROM statement hooks
+  ******************************************************************/
+
+ /*
+  * pgaceCopyTable
+  *
+  * This hook is invoked before executing COPY TO/COPY FROM statement,
+  * to give the guest a chance to check tables/columns appeared in.
+  *
+  * arguments:
+  * - rel is the target relation of this COPY TO/FROM statement.
+  *   It can be NULL, when COPY (SELECT ...) TO ... is given.
+  * - attNumList is a list of attribute number
+  * - isFrom is a bool to show the direction of the COPY
+  */
+ void
+ pgaceCopyTable(Relation rel, List *attNumList, bool isFrom)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlCopyTable(rel, attNumList, isFrom);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceCopyFile
+  *
+  * This hook is invoked just after a target file is opened
+  * at COPY TO/COPY FROM statement to give the guest a chance to
+  * check whether it allows to read/write the file.
+  *
+  * arguments:
+  * - rel is the target relation of this COPY TO/FROM statement.
+  *   It can be NULL, when COPY (SELECT ...) TO ... is given.
+  * - isFrom is a bool to show the direction of the COPY
+  * - fdesc is the file descriptor of the target file opened.
+  * - filename is the filename of fdesc
+  */
+ void
+ pgaceCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlCopyFile(rel, fdesc, filename, isFrom);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceCopyToTuple
+  *
+  * This hook is invoked just before output of a fetched tuple on
+  * processing COPY TO statement, to give the guest a chance to make
+  * a decision whether the given tuple is visible, or not.
+  * If it returns false, the given tuple is not exported, as if it
+  * does not exist on the target relation.
+  * Elsewhere,
+  *
+  * arguments:
+  * - rel is the target relation of this
+  * - attNumList is a list of attribute number
+  * - tuple is a tuple to be checked
+  */
+ bool
+ pgaceCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple)
+ {
+     /* A wired DAC check */
+     if (!rowaclCopyToTuple(rel, attNumList, tuple))
+         return false;
+
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlCopyToTuple(rel, attNumList, tuple);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return true;
+ }
+
+ /******************************************************************
+  * Loadable shared library module hooks
+  ******************************************************************/
+
+ /*
+  * pgaceLoadSharedModule
+  *
+  * This hook is invoked before loading a shared library module,
+  * to give the guest a change to confirm whether the required
+  * module is safe, or not.
+  *
+  * This hook can be also invoked implicitly when a user tries
+  * to call a function implemented within external modules.
+  */
+ void
+ pgaceLoadSharedModule(const char *filename)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLoadSharedModule(filename);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /******************************************************************
+  * Binary Large Object (BLOB) hooks
+  ******************************************************************/
+
+ /*
+  * pgaceLargeObjectCreate
+  *
+  * This hooks is invoked just before the first tuple of a new large
+  * object is inserted, to give the guest a change to make its
+  * decision and attach proper security context for the tuple.
+  *
+  * The argument of rel is the opened pg_largeobject system catalog.
+  */
+ void
+ pgaceLargeObjectCreate(Relation rel, HeapTuple tuple)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLargeObjectCreate(rel, tuple);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceLargeObjectDrop
+  *
+  * This hook is invoked just before each tuple of a large object
+  * are deleted, to give the guest a change to make its decision.
+  *
+  * The argument of pgaceItem is an opaque data, the guest can
+  * use it discreationally.
+  */
+ void
+ pgaceLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLargeObjectDrop(rel, tuple, pgaceItem);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceLargeObjectRead
+  *
+  * This hook is invoked at the head of lo_read().
+  * If the guest allows a large object to have non-uniform security
+  * attributes (not a unique one for each page frame), using HeapTuple
+  * related hooks are more recommendable.
+  */
+ void
+ pgaceLargeObjectRead(LargeObjectDesc *lodesc, int length)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLargeObjectRead(lodesc, length);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceLargeObjectWrite
+  *
+  * This hook is invoked at the head of lo_write().
+  */
+ void
+ pgaceLargeObjectWrite(LargeObjectDesc *lodesc, int length)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLargeObjectWrite(lodesc, length);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceLargeObjectTruncate
+  *
+  * This hook is invoked at the head of lo_truncate().
+  */
+ void
+ pgaceLargeObjectTruncate(LargeObjectDesc *lodesc, int offset)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLargeObjectTruncate(lodesc, offset);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceLargeObjectImport
+  *
+  * This hook is invoked just before importing the given file.
+  */
+ void
+ pgaceLargeObjectImport(Oid loid, int fdesc, const char *filename)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLargeObjectImport(loid, fdesc, filename);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceLargeObjectExport
+  *
+  * This hook is invoked just before exporting the given large object.
+  */
+ void
+ pgaceLargeObjectExport(Oid loid, int fdesc, const char *filename)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             sepgsqlLargeObjectExport(loid, fdesc, filename);
+         break;
+ #endif
+     default:
+         break;
+     }
+ }
+
+ /*
+  * pgaceLargeObjectGetSecurity
+  *
+  * This hook is invoked when user requires to run lo_get_security()
+  * Note that PGACE assumes the security attribute of first page frame
+  * of large object represents its security attribute.
+  */
+ void
+ pgaceLargeObjectGetSecurity(Relation rel, HeapTuple tuple)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlLargeObjectGetSecurity(rel, tuple);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+     ereport(ERROR,
+             (errcode(ERRCODE_PGACE_ERROR),
+              errmsg("no enhanced security feature is available.")));
+ }
+
+ /*
+  * pgaceLargeObjectSetSecurity
+  *
+  * This hook is invoked when user requires to run lo_set_security(),
+  * for each tuple within a given large object, which have unchecked
+  * security attribute. In other word, PGACE does not require the guest
+  * to check permission toward same security attribute twice, or more.
+  */
+ void
+ pgaceLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+         {
+             sepgsqlLargeObjectSetSecurity(rel, newtup, oldtup);
+             return;
+         }
+         break;
+ #endif
+     default:
+         break;
+     }
+     ereport(ERROR,
+             (errcode(ERRCODE_PGACE_ERROR),
+              errmsg("no enhanced security feature is available.")));
+ }
+
+ /******************************************************************
+  * Security Label hooks
+  ******************************************************************/
+
+ /*
+  * pgaceTupleDescHasRowAcl
+  *
+  * This hook enables to control the value of TupleDesc->tdhasrowacl.
+  *
+  */
+ bool
+ pgaceTupleDescHasRowAcl(Relation rel, List *relopts)
+ {
+     return rowaclTupleDescHasRowAcl(rel, relopts);
+ }
+
+ /*
+  * pgaceTupleDescHasSecurity
+  *
+  * This hook enables to control the value in TupleDesc->tdhasseclabel.
+  * If it returns true, sizeof(Oid) bytes are allocated at the header
+  * of HeapTupleHeader structure.
+  *
+  * The 'rel' argument can be NULL, when we make a decision for newly
+  * created relation via SELECT INTO/CREATE TABLE AS. In this case,
+  * unparsed relation options are delivered.
+  */
+ bool
+ pgaceTupleDescHasSecLabel(Relation rel, List *relopts)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlTupleDescHasSecLabel(rel, relopts);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return false;
+ }
+
+ /*
+  * pgaceTranslateSecurityLabelIn
+  *
+  * This hook enables the guest to translate a text representation
+  * of a given security attribute in external format into internal
+  * raw-format. It is invoked when user specifies security attribute
+  * explicitly in INSERT/UPDATE statement, to translate it into
+  * raw-internal format.
+  *
+  * It has to return a palloc()'ed Cstring, as a raw-internal format.
+  *
+  * In SE-PostgreSQL it supports translation in MLS/MCS labels like:
+  *   "system_u:object_r:sepgsql_table_t:SystemHigh"
+  *     <-->  "system_u:object_r:sepgsql_table_t:s0:c0.c1023"
+  */
+ char *
+ pgaceTranslateSecurityLabelIn(char *seclabel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlTranslateSecurityLabelIn(seclabel);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return seclabel;
+ }
+
+ /*
+  * pgaceTranslateSecurityLabelOut
+  *
+  * This hook enables the guest to translate a text representation
+  * of a given security attribute in internal format into cosmetic
+  * external format.
+  */
+ char *
+ pgaceTranslateSecurityLabelOut(char *seclabel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlTranslateSecurityLabelOut(seclabel);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return seclabel;
+ }
+
+ /*
+  * pgaceValidateSecurityLabel
+  *
+  * This hook enables the guest to validate the given security attribute
+  * in raw-internal format.
+  */
+ bool
+ pgaceCheckValidSecurityLabel(char *seclabel)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlCheckValidSecurityLabel(seclabel);
+         break;
+ #endif
+     default:
+         break;
+     }
+     return false;
+ }
+
+ /*
+  * pgaceUnlabeledSecurityLabel
+  *
+  * This hooks allows the guest to provide an alternative security
+  * attribute, when no valid text representation found on pg_security.
+  * The hooks has to return an alternative attribute palloc()'ed.
+  */
+ char *
+ pgaceUnlabeledSecurityLabel(void)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlUnlabeledSecurityLabel();
+         break;
+ #endif
+     default:
+         break;
+     }
+     return NULL;
+ }
+
+ /*
+  * pgaceSecurityLabelOfLabel
+  *
+  * This hook has to return the security attribute of a newly inserted
+  * tuple withing pg_security system catalog. Note that we need a special
+  * handling in the case of pg_security. If a new tuple requires a quite
+  * new security attribute which is not on pg_security, its insertion
+  * invokes one more insertion into pg_security. In the result, it makes
+  * infinite function invocation.
+  * This hook is used to avoid such a situation. The guest has to return
+  * a text represented security attribute.
+  */
+ char *
+ pgaceSecurityLabelOfLabel(void)
+ {
+     switch (pgace_feature)
+     {
+ #ifdef HAVE_SELINUX
+     case PGACE_FEATURE_SELINUX:
+         if (sepgsqlIsEnabled())
+             return sepgsqlSecurityLabelOfLabel();
+         break;
+ #endif
+     default:
+         break;
+     }
+     return NULL;
+ }
diff -Nrpc base/src/backend/security/rowacl/rowacl.c sepgsql/src/backend/security/rowacl/rowacl.c
*** base/src/backend/security/rowacl/rowacl.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/rowacl/rowacl.c    Fri Jan 16 10:31:05 2009
***************
*** 0 ****
--- 1,721 ----
+ /*
+  * src/backend/rowacl/rowacl.c
+  *   Row-level Database ACLs support
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+
+ #include "access/reloptions.h"
+ #include "catalog/namespace.h"
+ #include "catalog/pg_type.h"
+ #include "commands/defrem.h"
+ #include "miscadmin.h"
+ #include "nodes/nodeFuncs.h"
+ #include "parser/parsetree.h"
+ #include "security/pgace.h"
+ #include "storage/bufmgr.h"
+ #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
+ #include "utils/guc.h"
+ #include "utils/inval.h"
+ #include "utils/lsyscache.h"
+ #include "utils/memutils.h"
+ #include "utils/syscache.h"
+
+ #define ROWACL_ALL_PRIVS    (ACL_SELECT | ACL_UPDATE | ACL_DELETE | ACL_REFERENCES)
+
+ static void walkOnQueryTree(Query *query);
+
+ /******************************************************************
+  * Mark appeared Query/Sub-Query
+  ******************************************************************/
+
+ static bool walkOnNodeTree(Node *node, Query *query)
+ {
+     if (!node)
+         return false;
+
+     if (IsA(node, RangeTblRef))
+     {
+         RangeTblRef *rtr = (RangeTblRef *) node;
+         RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
+
+         if (rte->rtekind == RTE_RELATION &&
+             rtr->rtindex != query->resultRelation)
+         {
+             rte->pgaceTuplePerms |= ACL_SELECT;
+         }
+         else if (rte->rtekind == RTE_SUBQUERY)
+         {
+             walkOnQueryTree(rte->subquery);
+         }
+     }
+     else if (IsA(node, Query))
+     {
+         walkOnQueryTree((Query *) node);
+     }
+     else if (IsA(node, SortGroupClause))
+     {
+         /*
+          * expression_tree_walker() does not understand
+          * T_SortGroupClause node, so we have to avoid it
+          * walking on the node type.
+          */
+         return false;
+     }
+
+     return expression_tree_walker(node, walkOnNodeTree, (void *) query);
+ }
+
+ static void walkOnQueryTree(Query *query)
+ {
+     RangeTblEntry *rte;
+
+     if (query->commandType == CMD_UPDATE)
+     {
+         rte = rt_fetch(query->resultRelation, query->rtable);
+         rte->pgaceTuplePerms |= ACL_UPDATE;
+         if (query->returningList)
+             rte->pgaceTuplePerms |= ACL_SELECT;
+     }
+     else if (query->commandType == CMD_DELETE)
+     {
+         rte = rt_fetch(query->resultRelation, query->rtable);
+         rte->pgaceTuplePerms |= ACL_DELETE;
+         if (query->returningList)
+             rte->pgaceTuplePerms |= ACL_SELECT;
+     }
+     query_tree_walker(query,
+                       walkOnNodeTree,
+                       (void *) query, 0);
+ }
+
+ List *rowaclPostQueryRewrite(List *queryList)
+ {
+     ListCell *l;
+
+     foreach (l, queryList)
+     {
+         Query *query = (Query *) lfirst(l);
+
+         Assert(IsA(query, Query));
+
+         if (query->commandType == CMD_SELECT ||
+             query->commandType == CMD_UPDATE ||
+             query->commandType == CMD_DELETE)
+             walkOnQueryTree(query);
+     }
+
+     return queryList;
+ }
+
+ /******************************************************************
+  * Cache boost row-level ACLs checks
+  ******************************************************************/
+
+ static MemoryContext RowAclMemCtx;
+
+ #define ROWACL_CACHE_SLOT_NUM       128
+ static List *rowaclCacheSlot[ROWACL_CACHE_SLOT_NUM];
+
+ static void rowaclCacheReset(void)
+ {
+     int i;
+
+     MemoryContextReset(RowAclMemCtx);
+
+     for (i=0; i < ROWACL_CACHE_SLOT_NUM; i++)
+         rowaclCacheSlot[i] = NIL;
+ }
+
+ typedef struct {
+     Oid        relid;
+     Oid        userid;
+     Oid        aclid;
+     AclMode    privs;
+ } rowaclCacheItem;
+
+ static int rowaclCacheHash(Oid relid, Oid userid, Oid aclid)
+ {
+     Oid keys[3] = { relid, userid, aclid };
+
+     return tag_hash(keys, sizeof(keys)) % ROWACL_CACHE_SLOT_NUM;
+ }
+
+ static void rowaclCacheInsert(Oid relid, Oid userid, Oid aclid, AclMode privs)
+ {
+     MemoryContext oldctx;
+     rowaclCacheItem *aci;
+     int index = rowaclCacheHash(relid, userid, aclid);
+
+     oldctx = MemoryContextSwitchTo(RowAclMemCtx);
+
+     aci = palloc0(sizeof(rowaclCacheItem));
+     aci->relid = relid;
+     aci->userid = userid;
+     aci->aclid = aclid;
+     aci->privs = privs;
+
+     rowaclCacheSlot[index] = lappend(rowaclCacheSlot[index], aci);
+
+     MemoryContextSwitchTo(oldctx);
+ }
+
+ static bool rowaclCacheLookup(Oid relid, Oid userid, Oid aclid, AclMode *privs)
+ {
+     ListCell *l;
+     int index = rowaclCacheHash(relid, userid, aclid);
+
+     foreach (l, rowaclCacheSlot[index])
+     {
+         rowaclCacheItem *aci = lfirst(l);
+
+         if (aci->relid == relid &&
+             aci->userid == userid &&
+             aci->aclid == aclid)
+         {
+             *privs = aci->privs;
+             return true;
+         }
+     }
+
+     return false;
+ }
+
+ static void
+ rowaclSyscacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
+ {
+     rowaclCacheReset();
+ }
+
+ void rowaclInitialize(bool is_bootstrap)
+ {
+     RowAclMemCtx = AllocSetContextCreate(TopMemoryContext,
+                                          "Row-level ACL result cache",
+                                          ALLOCSET_DEFAULT_MINSIZE,
+                                          ALLOCSET_DEFAULT_INITSIZE,
+                                          ALLOCSET_DEFAULT_MAXSIZE);
+
+     CacheRegisterSyscacheCallback(AUTHOID,
+                                   rowaclSyscacheCallback, 0);
+     CacheRegisterSyscacheCallback(RELOID,
+                                   rowaclSyscacheCallback, 0);
+     rowaclCacheReset();
+ }
+
+ /******************************************************************
+  * Row-level access controls
+  ******************************************************************/
+
+ struct rowaclUserInfoType {
+     Oid userid;
+     bool abort_on_error;
+ };
+ struct rowaclUserInfoType *rowaclUserInfo = NULL;
+
+ Datum rowaclBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid)
+ {
+     Datum save_pgace = PointerGetDatum(rowaclUserInfo);
+     struct rowaclUserInfoType *uinfo
+         = palloc0(sizeof(struct rowaclUserInfoType));
+     uinfo->userid = save_userid;
+     uinfo->abort_on_error = is_primary;
+
+     rowaclUserInfo = uinfo;
+
+     return save_pgace;
+ }
+
+ void rowaclEndPerformCheckFK(Relation rel, Datum save_pgace)
+ {
+     rowaclUserInfo = (struct rowaclUserInfoType *) DatumGetPointer(save_pgace);
+ }
+
+ static bool
+ rowaclCheckPermission(Relation rel, HeapTuple tuple, AclMode required)
+ {
+     Oid relid = RelationGetRelid(rel);
+     Oid ownerid = RelationGetForm(rel)->relowner;
+     Oid userid = GetUserId();
+     Oid aclid = HeapTupleGetRowAcl(tuple);
+     AclMode privs;
+
+     if (rowaclUserInfo)
+     {
+         userid = rowaclUserInfo->userid;
+
+         /*
+          * If ACL_SELECT is given within FK constraint checks,
+          * its privilege is replaced to ACL_REFERENCES.
+          */
+         if (required & ACL_SELECT)
+         {
+             required &= ~ACL_SELECT;
+             required |= ACL_REFERENCES;
+         }
+     }
+
+     if (!rowaclCacheLookup(relid, userid, aclid, &privs))
+     {
+         /* Superusers/Owner bypass all permission checking */
+         if (superuser_arg(userid) || userid == ownerid)
+         {
+             privs = ROWACL_ALL_PRIVS;
+         }
+         else
+         {
+             Acl *acl = rowaclSidToSecurityAcl(aclid, ownerid);
+
+             privs = aclmask(acl, userid, ownerid, ROWACL_ALL_PRIVS, ACLMASK_ALL);
+         }
+         rowaclCacheInsert(relid, userid, aclid, privs);
+     }
+
+     if ((privs & required) == required)
+         return true;
+
+     if (rowaclUserInfo && rowaclUserInfo->abort_on_error)
+         ereport(ERROR,
+                 (errcode(ERRCODE_ROWACL_ERROR),
+                  errmsg("access violation in row-level acl")));
+
+     return false;
+ }
+
+ bool rowaclExecScan(Scan *scan, Relation rel, TupleTableSlot *slot)
+ {
+     AclMode required = scan->pgaceTuplePerms & ROWACL_ALL_PRIVS;
+     HeapTuple tuple;
+
+     if (required==0 || !RelationGetRowLevelAcl(rel))
+         return true;
+
+     tuple = ExecMaterializeSlot(slot);
+
+     return rowaclCheckPermission(rel, tuple, required);
+ }
+
+ bool rowaclCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple)
+ {
+     if (!RelationGetRowLevelAcl(rel))
+         return true;
+
+     return rowaclCheckPermission(rel, tuple, ACL_SELECT);
+ }
+
+ /******************************************************************
+  * Check ownership of tuples
+  ******************************************************************/
+ bool rowaclHeapTupleInsert(Relation rel, HeapTuple tuple,
+                            bool is_internal, bool with_returning)
+ {
+     if (!HeapTupleHasRowAcl(tuple))
+         return true;
+
+     if (OidIsValid(HeapTupleGetRowAcl(tuple)))
+     {
+         if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
+             ereport(ERROR,
+                     (errcode(ERRCODE_ROWACL_ERROR),
+                      errmsg("only general relation can have row-level ACL")));
+         if (!is_internal &&
+             !pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
+             ereport(ERROR,
+                     (errcode(ERRCODE_ROWACL_ERROR),
+                      errmsg("Only owner or superuser can set ACL")));
+     }
+     else
+     {
+         char *default_row_acl = RelationGetDefaultRowAcl(rel);
+
+         if (default_row_acl)
+         {
+             FmgrInfo finfo;
+             Datum aclDat;
+             Oid sid;
+
+             fmgr_info(F_ARRAY_IN, &finfo);
+             aclDat = FunctionCall3(&finfo,
+                                    CStringGetDatum(default_row_acl),
+                                    ObjectIdGetDatum(ACLITEMOID),
+                                    Int32GetDatum(-1));
+             sid = rowaclSecurityAclToSid(DatumGetAclP(aclDat));
+             HeapTupleSetRowAcl(tuple, sid);
+         }
+     }
+
+     return true;
+ }
+
+ static HeapTuple
+ getHeapTupleFromItemPointer(Relation rel, ItemPointer tid)
+ {
+     /*
+      * obtain an old tuple
+      */
+     Buffer      buffer;
+     PageHeader  dp;
+     ItemId      lp;
+     HeapTupleData tuple;
+     HeapTuple   oldtup;
+
+     buffer = ReadBuffer(rel, ItemPointerGetBlockNumber(tid));
+     LockBuffer(buffer, BUFFER_LOCK_SHARE);
+
+     dp = (PageHeader) BufferGetPage(buffer);
+     lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+
+     Assert(ItemIdIsNormal(lp));
+
+     tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
+     tuple.t_len = ItemIdGetLength(lp);
+     tuple.t_self = *tid;
+     tuple.t_tableOid = RelationGetRelid(rel);
+     oldtup = heap_copytuple(&tuple);
+
+     LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+     ReleaseBuffer(buffer);
+
+     return oldtup;
+ }
+
+ bool rowaclHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
+                            bool is_internal, bool with_returning)
+ {
+     HeapTuple oldtup = getHeapTupleFromItemPointer(rel, otid);
+
+     if (!HeapTupleHasRowAcl(newtup))
+         return true;
+
+     if (!OidIsValid(HeapTupleGetRowAcl(newtup)))
+     {
+         /* preserve old ACL */
+         HeapTupleSetRowAcl(newtup, HeapTupleGetRowAcl(oldtup));
+     }
+     else if (HeapTupleGetRowAcl(newtup) != HeapTupleGetRowAcl(oldtup))
+     {
+         if (!is_internal &&
+             !pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
+             ereport(ERROR,
+                     (errcode(ERRCODE_ROWACL_ERROR),
+                      errmsg("Only owner or superuser can set ACL")));
+     }
+     return true;
+ }
+
+ bool rowaclHeapTupleDelete(Relation rel, ItemPointer otid,
+                            bool is_internal, bool with_returning)
+ {
+     /*
+      * Do nothing here
+      */
+     return true;
+ }
+
+ /******************************************************************
+  * Relation Options
+  ******************************************************************/
+ void
+ rawaclValidateDefaultRowAclRelopt(const char *value)
+ {
+     FmgrInfo finfo;
+     Datum acldat;
+
+     /*
+      * If given default row-acl in reloptions is not valid,
+      * aclitemin can raise an error.
+      */
+     fmgr_info(F_ARRAY_IN, &finfo);
+     acldat = FunctionCall3(&finfo,
+                            CStringGetDatum(value),
+                            ObjectIdGetDatum(ACLITEMOID),
+                            Int32GetDatum(-1));
+     pfree(DatumGetAclP(acldat));
+ }
+
+ /******************************************************************
+  * Row-level ACLs management
+  ******************************************************************/
+
+ bool rowaclTupleDescHasRowAcl(Relation rel, List *relopts)
+ {
+     ListCell *l;
+
+     if (rel)
+         return RelationGetRowLevelAcl(rel);
+
+     /* SELECT INTO cases */
+     foreach (l, relopts)
+     {
+         DefElem *def = (DefElem *) lfirst(l);
+
+         if (pg_strcasecmp(def->defname, "row_level_acl") == 0)
+             return defGetBoolean(def);
+     }
+
+     return false;
+ }
+
+ static Acl *
+ rowaclDefaultAclArray(Oid ownerId)
+ {
+     Acl *acl;
+     AclItem *aip;
+
+     /*
+      * All permissions to public in default
+      */
+     acl = allocacl(1);
+     aip = ACL_DAT(acl);
+     aip->ai_grantee = ACL_ID_PUBLIC;
+     aip->ai_grantor = ownerId;
+     aip->ai_privs = ROWACL_ALL_PRIVS;
+
+     return acl;
+ }
+
+ static bool
+ rowaclCheckValidSecurityAcl(const char *raw_acl)
+ {
+     char *copy, *tok, *sv = NULL;
+     AclItem ai;
+
+     if (strncmp(raw_acl, "acl:", 4) != 0)
+         return false;
+
+     copy = pstrdup(raw_acl + 4);
+     for (tok = strtok_r(copy, ",", &sv);
+          tok;
+          tok = strtok_r(NULL, ",", &sv))
+     {
+         if (sscanf(tok, "%x=%x/%x",
+                    &ai.ai_grantee,
+                    &ai.ai_privs,
+                    &ai.ai_grantor) != 3)
+             return false;
+     }
+
+     return true;
+ }
+
+ static Acl *
+ rawAclTextToAclArray(const char *raw_acl)
+ {
+     Acl *acl;
+     AclItem *aip;
+     char *copy, *tok, *sv = NULL;
+     int num = 0;
+
+     Assert(strncmp(raw_acl, "acl:", 4) == 0);
+
+     copy = pstrdup(raw_acl + 4);
+     aip = palloc(strlen(copy) * sizeof(AclItem) / 4);
+     for (tok = strtok_r(copy, ",", &sv);
+          tok;
+          tok = strtok_r(NULL, ",", &sv))
+     {
+         if (sscanf(tok, "%x=%x/%x",
+                    &aip[num].ai_grantee,
+                    &aip[num].ai_privs,
+                    &aip[num].ai_grantor) != 3)
+             continue;
+         num++;
+     }
+
+     acl = allocacl(num);
+     memcpy(ACL_DAT(acl), aip, num * sizeof(AclItem));
+
+     pfree(aip);
+     pfree(copy);
+
+     check_acl(acl);
+
+     return acl;
+ }
+
+ static char *
+ rawAclTextFromAclArray(Acl *acl)
+ {
+     AclItem *aip = ACL_DAT(acl);
+     char *raw_acl = palloc0(ACL_NUM(acl) * 30 + 10); /* enough length */
+     int i, ofs;
+
+     ofs = sprintf(raw_acl, "acl:");
+
+     for (i = 0; i < ACL_NUM(acl); i++)
+     {
+         if ((aip[i].ai_privs & ROWACL_ALL_PRIVS) != aip[i].ai_privs)
+             ereport(ERROR,
+                     (errcode(ERRCODE_ROWACL_ERROR),
+                      errmsg("unsupported privileges in row_acl: %04x",
+                             aip[i].ai_privs & ~ROWACL_ALL_PRIVS)));
+
+         ofs += sprintf(raw_acl + ofs,
+                        "%s%x=%x/%x",
+                        (i == 0 ? "" : ","),
+                        aip[i].ai_grantee,
+                        aip[i].ai_privs,
+                        aip[i].ai_grantor);
+     }
+
+     return raw_acl;
+ }
+
+ Acl *rowaclSidToSecurityAcl(Oid sid, Oid ownerId)
+ {
+     char *raw_acl
+         = pgaceLookupSecurityLabel(sid);
+
+     if (!raw_acl || !rowaclCheckValidSecurityAcl(raw_acl))
+         return rowaclDefaultAclArray(ownerId);
+
+     return rawAclTextToAclArray(raw_acl);
+ }
+
+ Oid rowaclSecurityAclToSid(Acl *acl)
+ {
+     char *raw_acl
+         = rawAclTextFromAclArray(acl);
+
+     return pgaceLookupSecurityId(raw_acl);
+ }
+
+ Datum rowaclHeapGetSecurityAclSysattr(HeapTuple tuple)
+ {
+     HeapTuple rtup;
+     Oid        rowaclSid = InvalidOid;
+     Oid        relowner;
+     char    relkind;
+     Datum    reloptions;
+     bool    isnull;
+
+     rtup = SearchSysCache(RELOID,
+                           ObjectIdGetDatum(tuple->t_tableOid),
+                           0, 0, 0);
+     if (!HeapTupleIsValid(rtup))
+         elog(ERROR, "cache lookup failed for relation %u", tuple->t_tableOid);
+
+     relowner = ((Form_pg_class) GETSTRUCT(rtup))->relowner;
+     relkind = ((Form_pg_class) GETSTRUCT(rtup))->relkind;
+     reloptions = SysCacheGetAttr(RELOID, rtup,
+                                  Anum_pg_class_reloptions,
+                                  &isnull);
+     if (!isnull)
+     {
+         StdRdOptions *RdOpts
+             = (StdRdOptions *) heap_reloptions(relkind, reloptions, false);
+
+         if (RdOpts && RdOpts->row_level_acl)
+             rowaclSid = HeapTupleGetRowAcl(tuple);
+     }
+
+     ReleaseSysCache(rtup);
+
+     return PointerGetDatum(rowaclSidToSecurityAcl(rowaclSid, relowner));
+ }
+
+ /******************************************************************
+  * SQL functions
+  ******************************************************************/
+
+ static Datum rowacl_grant_revoke(PG_FUNCTION_ARGS, bool grant, bool cascade)
+ {
+     char *input, *tok, *sv = NULL;
+     HeapTuple tuple;
+     Acl *acl;
+     Oid ownerid;
+     List *grantees = NIL;
+     AclMode privileges = 0;
+
+     /*
+      * Get owner Id;
+      */
+     tuple = SearchSysCache(RELOID,
+                            PG_GETARG_DATUM(0), 0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "cache lookup failed for relation %u",
+              PG_GETARG_OID(0));
+
+     ownerid = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
+     ReleaseSysCache(tuple);
+
+     /*
+      * Extract Acl array
+      */
+     acl = PG_GETARG_ACL_P(1);
+
+     /*
+      * Extract usernames
+      */
+     input = TextDatumGetCString(PG_GETARG_TEXT_P(2));
+     for (tok = strtok_r(input, ",", &sv);
+          tok;
+          tok = strtok_r(NULL, ",", &sv))
+     {
+         if (strcasecmp(tok, "public") == 0)
+             grantees = lappend_oid(grantees, ACL_ID_PUBLIC);
+         else
+         {
+             Oid roleid = get_roleid(tok);
+
+             if (roleid == InvalidOid)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_ROWACL_ERROR),
+                          errmsg("%s is not a valid identifier", tok)));
+
+             grantees = lappend_oid(grantees, roleid);
+         }
+     }
+     /*
+      * Extract permission names
+      */
+     input = TextDatumGetCString(PG_GETARG_TEXT_P(3));
+     for (tok = strtok_r(input, ",", &sv);
+          tok;
+          tok = strtok_r(NULL, ",", &sv))
+     {
+         if (strcasecmp(tok, "all") == 0)
+             privileges |= ROWACL_ALL_PRIVS;
+         else if (strcasecmp(tok, "select") == 0)
+             privileges |= ACL_SELECT;
+         else if (strcasecmp(tok, "update") == 0)
+             privileges |= ACL_UPDATE;
+         else if (strcasecmp(tok, "delete") == 0)
+             privileges |= ACL_DELETE;
+         else if (strcasecmp(tok, "references") == 0)
+             privileges |= ACL_REFERENCES;
+         else
+             ereport(ERROR,
+                     (errcode(ERRCODE_ROWACL_ERROR),
+                      errmsg("%s is not a valid permission", tok)));
+     }
+
+     /*
+      * Merge ACL
+      */
+     acl = merge_acl_with_grant(acl, grant, false, cascade,
+                                grantees, privileges,
+                                GetUserId(), ownerid);
+
+     PG_RETURN_ACL_P(acl);
+ }
+
+ Datum
+ rowacl_grant(PG_FUNCTION_ARGS)
+ {
+     return rowacl_grant_revoke(fcinfo, true, false);
+ }
+
+ Datum
+ rowacl_revoke(PG_FUNCTION_ARGS)
+ {
+     return rowacl_grant_revoke(fcinfo, false, false);
+ }
+
+ Datum
+ rowacl_revoke_cascade(PG_FUNCTION_ARGS)
+ {
+     return rowacl_grant_revoke(fcinfo, false, true);
+ }
diff -Nrpc base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security/sepgsql/avc.c
*** base/src/backend/security/sepgsql/avc.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/sepgsql/avc.c    Thu Jan 22 14:09:37 2009
***************
*** 0 ****
--- 1,1200 ----
+ /*
+  * src/backend/security/sepgsql/avc.c
+  *      SE-PostgreSQL userspace access vector cache
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+
+ #include "access/hash.h"
+ #include "libpq/pqsignal.h"
+ #include "postmaster/postmaster.h"
+ #include "security/pgace.h"
+ #include "storage/ipc.h"
+ #include "storage/lwlock.h"
+ #include "utils/memutils.h"
+ #include "utils/syscache.h"
+ #include <linux/netlink.h>
+ #include <linux/selinux_netlink.h>
+ #include <signal.h>
+ #include <unistd.h>
+
+ /*
+  * uAVC: userspace Access Vector Cache
+  *
+  * SE-PostgreSQL makes inqueries for SELinux to check whether the security
+  * policy allows the required action, or not. However, it need to invoke
+  * system call because SELinux is a kernel feature and it hold its security
+  * policy in the kernel memory.
+  *
+  * uAVC enables to reduce the number of kernel invocation, with caching
+  * the result of inquiries. When we have to make a decision based on the
+  * security policy of SELinux, it tries to find up an appropriate cache
+  * entry on the uAVC. If exist, we don't need to invoke a system call
+  * and can reduce unnecessary overhead.
+  *
+  * If not exist, SE-PostgreSQL makes a new cache entry based on the
+  * result of inquiries, and chains it on uAVC to prepare the following
+  * decision makings.
+  *
+  * uAVC has a version number to check whether it is now valid, or not.
+  * Not need to say, uAVC cache entry has to be invalid just after
+  * policy reloaded or state change.
+  * If it is not match the latest one, updated by the policy state
+  * monitoring process, uAVC has to be reseted.
+  */
+
+ /*
+  * Dynamic object class/access vector mapping
+  *
+  * SELinux exports the list of object classes (it means kind of object, like
+  * file or table) and access vectors (it means permission set, like read,
+  * select, ...) under /selinux/class.
+  * It enables to provide userspace object managers a interface to get what
+  * codes should be used to ask SELinux.
+  *
+  * libselinux provides an API to translate a string expression and a code
+  * used by the loaded security policy. These correspondences are not assured
+  * over the bound of policy loading, so we have to reload the mapping after
+  * in-kernel policy is reloaded, or its state is changed.
+  */
+ static struct
+ {
+     struct
+     {
+         const char *name;
+         security_class_t internal;
+     } tclass;
+     struct
+     {
+         char       *name;
+         access_vector_t internal;
+     } av_perms[sizeof(access_vector_t) * 8];
+ } selinux_catalog[] = {
+     {
+         { "db_database", SECCLASS_DB_DATABASE},
+         {
+             { "create",            DB_DATABASE__CREATE },
+             { "drop",            DB_DATABASE__DROP },
+             { "getattr",        DB_DATABASE__GETATTR },
+             { "setattr",        DB_DATABASE__SETATTR },
+             { "relabelfrom",    DB_DATABASE__RELABELFROM },
+             { "relabelto",        DB_DATABASE__RELABELTO },
+             { "access",            DB_DATABASE__ACCESS },
+             { "install_module",    DB_DATABASE__INSTALL_MODULE },
+             { "load_module",    DB_DATABASE__LOAD_MODULE },
+             { "get_param",        DB_DATABASE__GET_PARAM },
+             { "set_param",        DB_DATABASE__SET_PARAM },
+             { NULL, 0UL },
+         }
+     },
+     {
+         { "db_table", SECCLASS_DB_TABLE},
+         {
+             { "create",            DB_TABLE__CREATE },
+             { "drop",            DB_TABLE__DROP },
+             { "getattr",        DB_TABLE__GETATTR },
+             { "setattr",        DB_TABLE__SETATTR },
+             { "relabelfrom",    DB_TABLE__RELABELFROM },
+             { "relabelto",        DB_TABLE__RELABELTO },
+             { "use",               DB_TABLE__USE },
+             { "select",            DB_TABLE__SELECT },
+             { "update",            DB_TABLE__UPDATE },
+             { "insert",            DB_TABLE__INSERT },
+             { "delete",            DB_TABLE__DELETE },
+             { "lock",            DB_TABLE__LOCK },
+             { NULL, 0UL },
+         }
+     },
+     {
+         { "db_procedure", SECCLASS_DB_PROCEDURE},
+         {
+             { "create",            DB_PROCEDURE__CREATE },
+             { "drop",            DB_PROCEDURE__DROP },
+             { "getattr",        DB_PROCEDURE__GETATTR },
+             { "setattr",        DB_PROCEDURE__SETATTR },
+             { "relabelfrom",    DB_PROCEDURE__RELABELFROM },
+             { "relabelto",        DB_PROCEDURE__RELABELTO },
+             { "execute",        DB_PROCEDURE__EXECUTE },
+             { "entrypoint",        DB_PROCEDURE__ENTRYPOINT },
+             { "install",        DB_PROCEDURE__INSTALL },
+             { NULL, 0UL },
+         }
+     },
+     {
+         { "db_column", SECCLASS_DB_COLUMN},
+         {
+             { "create",            DB_COLUMN__CREATE },
+             { "drop",            DB_COLUMN__DROP },
+             { "getattr",        DB_COLUMN__GETATTR },
+             { "setattr",        DB_COLUMN__SETATTR },
+             { "relabelfrom",    DB_COLUMN__RELABELFROM },
+             { "relabelto",        DB_COLUMN__RELABELTO },
+             { "use",            DB_COLUMN__USE },
+             { "select",            DB_COLUMN__SELECT },
+             { "update",            DB_COLUMN__UPDATE },
+             { "insert",            DB_COLUMN__INSERT },
+             { NULL, 0UL },
+         }
+     },
+     {
+         { "db_tuple", SECCLASS_DB_TUPLE },
+         {
+             { "relabelfrom",    DB_TUPLE__RELABELFROM},
+             { "relabelto",        DB_TUPLE__RELABELTO},
+             { "use",            DB_TUPLE__USE},
+             { "select",            DB_TUPLE__SELECT},
+             { "update",            DB_TUPLE__UPDATE},
+             { "insert",            DB_TUPLE__INSERT},
+             { "delete",            DB_TUPLE__DELETE},
+             { NULL, 0UL},
+         }
+     },
+     {
+         { "db_blob", SECCLASS_DB_BLOB },
+         {
+             { "create",            DB_BLOB__CREATE},
+             { "drop",            DB_BLOB__DROP},
+             { "getattr",        DB_BLOB__GETATTR},
+             { "setattr",        DB_BLOB__SETATTR},
+             { "relabelfrom",    DB_BLOB__RELABELFROM},
+             { "relabelto",        DB_BLOB__RELABELTO},
+             { "read",            DB_BLOB__READ},
+             { "write",            DB_BLOB__WRITE},
+             { "import",            DB_BLOB__IMPORT},
+             { "export",            DB_BLOB__EXPORT},
+             { NULL, 0UL},
+         }
+     },
+ };
+
+ static MemoryContext AvcMemCtx;
+
+ #define AVC_HASH_NUM_SLOTS        256
+ #define AVC_HASH_NUM_NODES        600
+
+ static sig_atomic_t avc_version;
+ static bool avc_enforcing;
+
+ typedef struct
+ {
+     uint32    hash_key;
+
+     security_class_t tclass;
+     Oid        tsid;    /* target security context */
+
+     security_context_t ncontext;    /* newcontext */
+     Oid        nsid;    /* newly created security context */
+
+     access_vector_t allowed;
+     access_vector_t decided;
+     access_vector_t auditallow;
+     access_vector_t auditdeny;
+
+     bool    hot_cache;
+ } avc_datum;
+
+ typedef struct avc_page
+ {
+     struct avc_page *prev;
+     struct avc_page *next;
+
+     security_context_t    scontext;
+
+     List *slot[AVC_HASH_NUM_SLOTS];
+
+     uint32 lru_hint;
+ } avc_page;
+
+ static avc_page *current_avc_page = NULL;
+ static uint32 avc_datum_count = 0;
+
+ /*
+  * selinux_state
+  *
+  * This structure shows the global state of SELinux and its security
+  * policy, and it is assigned on shared memory region.
+  *
+  * The most significant variable is selinux_state->version.
+  * Any instance can refer this variable to confirm current sequence
+  * number of policy state, without locking.
+  *
+  * The only process able to update this variable is policy state
+  * monitoring process forked by postmaster. It can receive notifications
+  * from the kernel via netlink socket, and it update selinux_state->version
+  * to encourage any instance to reflush its uAVC.
+  *
+  * When we read rest of variable, we have to hold SepgsqlAvcLock LWlock
+  * as a reader. enforceing shows the current SELinux working mode.
+  * catalog shows the mapping set of security classes and access vectors.
+  */
+ struct
+ {
+     /*
+      * only state monitoring process can update version.
+      * any other process can read it without locks.
+      */
+     volatile sig_atomic_t version;
+
+     bool        enforcing;
+
+     struct
+     {
+         struct
+         {
+             security_class_t internal;
+             security_class_t external;
+         } tclass;
+         struct
+         {
+             access_vector_t internal;
+             access_vector_t external;
+         } av_perms[sizeof(access_vector_t) * 8];
+     } catalog[lengthof(selinux_catalog)];
+ }    *selinux_state = NULL;
+
+ Size
+ sepgsqlShmemSize(void)
+ {
+     return sizeof(*selinux_state);
+ }
+
+ /*
+  * load_class_av_mapping
+  *
+  * This function rebuild the mapping set of security classes and access
+  * vectors on selinux_state. It has to be invoked by the policy state
+  * monitoring process with SepgsqlAvcLock in LW_EXCLUSIVE.
+  */
+ static void
+ load_class_av_mapping(void)
+ {
+     int            i, j;
+
+     memset(selinux_state->catalog, 0, sizeof(selinux_state->catalog));
+
+     for (i = 0; i < lengthof(selinux_catalog); i++)
+     {
+         selinux_state->catalog[i].tclass.internal
+             = selinux_catalog[i].tclass.internal;
+         selinux_state->catalog[i].tclass.external
+             = string_to_security_class(selinux_catalog[i].tclass.name);
+
+         for (j = 0; selinux_catalog[i].av_perms[j].name; j++)
+         {
+             selinux_state->catalog[i].av_perms[j].internal
+                 = selinux_catalog[i].av_perms[j].internal;
+             selinux_state->catalog[i].av_perms[j].external
+                 = string_to_av_perm(selinux_state->catalog[i].tclass.external,
+                                     selinux_catalog[i].av_perms[j].name);
+         }
+     }
+ }
+
+ /*
+  * trans_to_external_tclass
+  *   translates internal object class number into external one
+  *   needed to communicate with in-kernel SELinux.
+  */
+ static security_class_t
+ trans_to_external_tclass(security_class_t i_tclass)
+ {
+     /* have to hold SepgsqlAvcLock with LW_SHARED */
+     int            i;
+
+     for (i = 0; i < lengthof(selinux_catalog); i++)
+     {
+         if (selinux_state->catalog[i].tclass.internal == i_tclass)
+             return selinux_state->catalog[i].tclass.external;
+     }
+     return i_tclass;            /* use it as is for kernel classes */
+ }
+
+ /*
+  * trans_to_internal_perms
+  *   translates external permission bits into internal ones
+  *   needed to understand the answer from in-kernel SELinux.
+  *   If in-kernel SELinux doesn't define required permissions,
+  *   it sets/clears undefined bits based on caller's preference.
+  *   It enables SE-PostgreSQL to work on legacy security policy.
+  */
+ static access_vector_t
+ trans_to_internal_perms(security_class_t e_tclass, access_vector_t e_perms,
+                         bool set_if_undefined)
+ {
+     /* have to hold SepgsqlAvcLock with LW_SHARED */
+     access_vector_t i_perms = 0UL;
+     access_vector_t undef_mask = 0UL;
+     int            i, j;
+
+     for (i = 0; i < lengthof(selinux_catalog); i++)
+     {
+         if (selinux_state->catalog[i].tclass.external != e_tclass)
+             continue;
+
+         for (j = 0; j < sizeof(access_vector_t) * 8; j++)
+         {
+             if (selinux_state->catalog[i].av_perms[j].external == 0)
+                 undef_mask |= (1UL << j);
+             else if (selinux_state->catalog[i].av_perms[j].external & e_perms)
+                 i_perms |= selinux_state->catalog[i].av_perms[j].internal;
+         }
+
+         if (set_if_undefined)
+             i_perms |= undef_mask;
+         else
+             i_perms &= ~undef_mask;
+
+         return i_perms;
+     }
+     return e_perms;                /* use it as is for kernel classes */
+ }
+
+ /*
+  * sepgsql_class_to_string
+  * sepgsql_av_perm_to_string
+  *   returns string representation of given object class and permission.
+  *   Please note that given code have internal ones, so we cannot use
+  *   libselinux's facility, because it assumes 'external code'.
+  *   (Kernel object classes are ABI, so these are stable.)
+  */
+ static const char *
+ sepgsql_class_to_string(security_class_t tclass)
+ {
+     int            i;
+
+     for (i = 0; i < lengthof(selinux_catalog); i++)
+     {
+         if (selinux_catalog[i].tclass.internal == tclass)
+             return selinux_catalog[i].tclass.name;
+     }
+     /*
+      * tclass is stable for kernel object classes.
+      */
+     return security_class_to_string(tclass);
+ }
+
+ static const char *
+ sepgsql_av_perm_to_string(security_class_t tclass, access_vector_t perm)
+ {
+     int            i, j;
+
+     for (i = 0; i < lengthof(selinux_catalog); i++)
+     {
+         if (selinux_catalog[i].tclass.internal == tclass)
+         {
+             char       *perm_name;
+
+             for (j = 0; (perm_name = selinux_catalog[i].av_perms[j].name); j++)
+             {
+                 if (selinux_catalog[i].av_perms[j].internal == perm)
+                     return perm_name;
+             }
+             return "unknown";
+         }
+     }
+     /*
+      * tclass/perms are stable for kernel object classes.
+      */
+     return security_av_perm_to_string(tclass, perm);
+ }
+
+ /*
+  * sepgsql_avc_reset
+  *   clears all uAVC entries and update its version.
+  */
+ static void
+ sepgsql_avc_reset(void)
+ {
+     MemoryContextReset(AvcMemCtx);
+
+     LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
+
+     avc_version = selinux_state->version;
+     switch (sepostgresql_mode)
+     {
+     case SEPGSQL_MODE_DEFAULT:
+         avc_enforcing = selinux_state->enforcing;
+         break;
+     case SEPGSQL_MODE_PERMISSIVE:
+         avc_enforcing = false;
+         break;
+     case SEPGSQL_MODE_ENFORCING:
+         avc_enforcing = false;
+         break;
+     default:
+         elog(FATAL, "SELinux: undefined state in SE-PostgreSQL");
+         break;
+     }
+
+     current_avc_page = NULL;
+
+     avc_datum_count = 0;
+
+     LWLockRelease(SepgsqlAvcLock);
+
+     sepgsqlAvcSwitchClientContext(sepgsqlGetClientContext());
+ }
+
+ /*
+  * sepgsql_avc_reclaim
+  *   reclaims recently unused uAVC entries, when the number of
+  *   caches overs AVC_HASH_NUM_NODES.
+  */
+ static void
+ sepgsql_avc_reclaim(void)
+ {
+     ListCell *l;
+     avc_page *avp;
+     avc_datum *cache;
+     int loop;
+
+     Assert(current_avc_page != NULL);
+
+     for (avp = current_avc_page->next; true; avp = avp->next)
+     {
+         for (loop = 0; loop < AVC_HASH_NUM_SLOTS; loop++)
+         {
+             if (avc_datum_count < AVC_HASH_NUM_NODES)
+                 return;
+
+             avp->lru_hint = (avp->lru_hint + 1) % AVC_HASH_NUM_SLOTS;
+             foreach (l, avp->slot[avp->lru_hint])
+             {
+                 cache = lfirst(l);
+
+                 if (cache->hot_cache)
+                 {
+                     cache->hot_cache = false;
+                     continue;
+                 }
+
+                 list_delete_ptr(avp->slot[avp->lru_hint], cache);
+                 pfree(cache);
+                 avc_datum_count--;
+             }
+         }
+     }
+ }
+
+ /*
+  * avc_audit_common
+  *   generates an audit message on the give string buffer based on
+  *   the given av_decision which means the resutl of permission checks.
+  */
+ static bool
+ avc_audit_common(char *buffer, uint32 buflen,
+                  avc_datum *cache, access_vector_t perms,
+                  const char *scontext, const char *tcontext, const char *objname)
+ {
+     access_vector_t denied, audited, mask;
+     security_context_t svcon, tvcon;
+     uint32 ofs = 0;
+
+     denied = perms & ~cache->allowed;
+     audited = denied ? (denied & cache->auditdeny) : (perms & cache->auditallow);
+
+     if (audited == 0)
+         return false;
+
+     ofs += snprintf(buffer + ofs, buflen - ofs, "%s {",
+                     denied ? "denied" : "granted");
+     for (mask = 1; mask != 0; mask <<= 1)
+     {
+         if ((audited & mask) != 0)
+             ofs += snprintf(buffer + ofs, buflen - ofs, " %s",
+                             sepgsql_av_perm_to_string(cache->tclass, mask));
+     }
+     ofs += snprintf(buffer + ofs, buflen - ofs, " } ");
+
+     if (!scontext)
+         svcon = sepgsqlTranslateSecurityLabelOut(current_avc_page->scontext);
+     else
+         svcon = sepgsqlTranslateSecurityLabelOut(scontext);
+
+     if (!tcontext)
+         tvcon = pgaceSidToSecurityLabel(cache->tsid);
+     else
+         tvcon = sepgsqlTranslateSecurityLabelOut(tcontext);
+
+     ofs += snprintf(buffer + ofs, buflen - ofs,
+                     "scontext=%s tcontext=%s tclass=%s",
+                     svcon, tvcon, sepgsql_class_to_string(cache->tclass));
+
+     pfree(svcon);
+     pfree(tvcon);
+     if (objname)
+         ofs += snprintf(buffer + ofs, buflen - ofs, " name=%s", objname);
+
+     return true;
+ }
+
+ /*
+  * avc_permission_common
+  *   makes decision and output audit messages based on given avc_datum.
+  *   If required permissions are not completely allowed, it raises an
+  *   error or returns 'false' when permissive mode.
+  */
+ static bool
+ avc_permission_common(avc_datum *cache, access_vector_t perms, bool abort,
+                       const char *scontext, const char *tcontext, const char *objname)
+ {
+     char audit_buffer[2048];
+     access_vector_t denied;
+     bool audit;
+     bool rc = true;
+
+     audit = avc_audit_common(audit_buffer, sizeof(audit_buffer),
+                              cache, perms, scontext, tcontext, objname);
+
+     denied = perms & ~cache->allowed;
+     if (!perms || denied)
+     {
+         if (avc_enforcing)
+             rc = false;
+         else
+         {
+             /*
+              * In permissive mode, once denied permissions are
+              * allowed to avoid a flood of denied logs.
+              */
+             cache->allowed |= perms;
+         }
+     }
+
+     if (audit)
+     {
+         ereport((!rc && abort) ? ERROR : NOTICE,
+                 (errcode(ERRCODE_SELINUX_AUDIT),
+                  errmsg("SELinux: %s", audit_buffer)));
+     }
+     else if (!rc && abort)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_AUDIT),
+                  errmsg("SELinux: security policy violation")));
+
+     return rc;
+ }
+
+ /*
+  * avc_make_entry
+  *   makes a query to in-kernel SELinux and an avc_datum object to
+  *   cache the result of SELinux's decision for access rights and
+  *   default security context.
+  */
+ #define avc_hash_key(tsid,tclass)    ((tsid) ^ ((tclass) << 2))
+
+ static avc_datum *
+ avc_make_entry(Oid tsid, security_class_t tclass)
+ {
+     security_context_t scontext, tcontext, ncontext;
+     security_class_t e_tclass;
+     MemoryContext oldctx = MemoryContextSwitchTo(AvcMemCtx);
+     struct av_decision avd;
+     avc_datum *cache;
+     uint32 hash_key, index;
+
+     hash_key = avc_hash_key(tsid, tclass);
+     index = hash_key % AVC_HASH_NUM_SLOTS;
+
+     cache = palloc0(sizeof(avc_datum));
+     cache->hash_key = hash_key;
+     cache->tsid = tsid;
+     cache->tclass = tclass;
+
+     scontext = current_avc_page->scontext;
+     tcontext = pgaceLookupSecurityLabel(tsid);
+     if (!tcontext || !pgaceCheckValidSecurityLabel(tcontext))
+         tcontext = pgaceUnlabeledSecurityLabel();
+
+     LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
+
+     e_tclass = trans_to_external_tclass(tclass);
+
+     if (security_compute_av_raw(scontext, tcontext, e_tclass, 0, &avd) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not compute av_decision: "
+                         "scontext=%s tcontext=%s tclass=%s",
+                         scontext, tcontext, sepgsql_class_to_string(tclass))));
+
+     cache->allowed = trans_to_internal_perms(e_tclass, avd.allowed, true);
+     cache->decided = trans_to_internal_perms(e_tclass, avd.decided, false);
+     cache->auditallow = trans_to_internal_perms(e_tclass, avd.auditallow, false);
+     cache->auditdeny = trans_to_internal_perms(e_tclass, avd.auditdeny, false);
+     cache->hot_cache = true;
+
+     if (security_compute_create_raw(scontext, tcontext, e_tclass, &ncontext) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not compute new context: "
+                         "scontext=%s tcontext=%s tclass=%s",
+                         scontext, tcontext, sepgsql_class_to_string(tclass))));
+     pfree(tcontext);
+
+     LWLockRelease(SepgsqlAvcLock);
+
+     PG_TRY();
+     {
+         cache->ncontext = pstrdup(ncontext);
+     }
+     PG_CATCH();
+     {
+         freecon(ncontext);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+
+     freecon(ncontext);
+
+     sepgsql_avc_reclaim();
+
+     current_avc_page->slot[index]
+         = lcons(cache, current_avc_page->slot[index]);
+
+     avc_datum_count++;
+
+     MemoryContextSwitchTo(oldctx);
+
+     return cache;
+ }
+
+ static avc_datum *avc_lookup(Oid tsid, security_class_t tclass)
+ {
+     avc_datum *cache = NULL;
+     uint32 hash_key, index;
+     ListCell *l;
+
+     /*
+      * check avc invalidation
+      */
+     if (avc_version != selinux_state->version)
+         sepgsql_avc_reset();
+
+     /*
+      * lookup avc entry
+      */
+     hash_key = avc_hash_key(tsid, tclass);
+     index = hash_key % AVC_HASH_NUM_SLOTS;
+
+     foreach (l, current_avc_page->slot[index])
+     {
+         cache = lfirst(l);
+         if (cache->hash_key == hash_key
+             && cache->tclass == tclass
+             && cache->tsid == tsid)
+         {
+             cache->hot_cache = true;
+             return cache;
+         }
+     }
+     return NULL;
+ }
+
+ /*
+  * sepgsqlAvcSwitchClientContext()
+  *   switches current avc_page.
+  *
+  * NOTE: In most cases, SE-PostgreSQL checks whether client is allowed
+  * to do required actions (like SELECT, UPDATE, ...) on the targets.
+  * Both of client and targets have its security context, and all rules
+  * are described as relationship between security context of a client,
+  * a target and kind of actions.
+  * However, the security context of client is unchanged in SE-PostgreSQL
+  * (an exception is invocation of trusted procedure), so we can omit
+  * to compare security context of client with entries of uAVC.
+  * The avc_page is a set of avc_datum sorted out by the security context
+  * of client, so we can lookup correct avc_datum on currently focued
+  * avc_page without comparing the security context of client.
+  * The reason why we don't not use a unique uAVC is the security context
+  * of client does not have its security identifier on pg_security, so
+  * it requires strcmp() for each entries, but it is heavier than integer
+  * comparisons.
+  * Thus we have to switch current avc_page, whenever the security context
+  * of client changes (via trusted procedure). It makes performance well
+  * in most cases.
+  */
+ void sepgsqlAvcSwitchClientContext(security_context_t newcontext)
+ {
+     MemoryContext oldctx;
+     avc_page *avp;
+     int i;
+
+     if (current_avc_page)
+     {
+         avp = current_avc_page;
+         do {
+             if (!strcmp(avp->scontext, newcontext))
+             {
+                 current_avc_page = avp;
+                 return;
+             }
+             avp = avp->next;
+         } while (avp != current_avc_page);
+     }
+
+     /* create a new avc_page */
+     oldctx = MemoryContextSwitchTo(AvcMemCtx);
+     avp = palloc0(sizeof(avc_page));
+     avp->scontext = pstrdup(newcontext);
+     MemoryContextSwitchTo(oldctx);
+
+     for (i=0; i < AVC_HASH_NUM_SLOTS; i++)
+         avp->slot[i] = NIL;
+
+     if (!current_avc_page)
+     {
+         avp->next = avp->prev = avp;
+     }
+     else
+     {
+         avp->next = current_avc_page;
+         avp->prev = current_avc_page->prev;
+         avp->prev->next = avp;
+         avp->next->prev = avp;
+     }
+     current_avc_page = avp;
+ }
+
+ /*
+  * sepgsqlClientHasPermission
+  *   checks client's privileges on given objects via uAVC.
+  *   It raised an error, if required actions are violated.
+  */
+ void
+ sepgsqlClientHasPermission(Oid tsid, security_class_t tclass,
+                            access_vector_t perms,
+                            const char *objname)
+ {
+     avc_datum *cache = avc_lookup(tsid, tclass);
+
+     if (!cache)
+         cache = avc_make_entry(tsid, tclass);
+
+     avc_permission_common(cache, perms, true, NULL, NULL, objname);
+ }
+
+ /*
+  * sepgsqlClientHasPermissionNoAbort
+  *   checks client's privileges on given objects via uAVC.
+  *   It returns false, if required actions are violated.
+  */
+ bool
+ sepgsqlClientHasPermissionNoAbort(Oid tsid, security_class_t tclass,
+                                   access_vector_t perms,
+                                   const char *objname)
+ {
+     avc_datum *cache = avc_lookup(tsid, tclass);
+
+     if (!cache)
+         cache = avc_make_entry(tsid, tclass);
+
+     return avc_permission_common(cache, perms, false, NULL, NULL, objname);
+ }
+
+ /*
+  * sepgsqlClientCreateSid
+  *   returns security identifier of newly created database object.
+  *   Please note that you don't have to invoke this function for
+  *   object classes except for database objects. It have a possibility
+  *   to make an entry on pg_security via pgaceSecurityLabelToSid(),
+  *   but it should be restricted to database object.
+  */
+ Oid
+ sepgsqlClientCreateSid(Oid tsid, security_class_t tclass)
+ {
+     avc_datum *cache = avc_lookup(tsid, tclass);
+
+     if (!cache || cache->nsid == InvalidOid)
+     {
+         if (!cache)
+             cache = avc_make_entry(tsid, tclass);
+         cache->nsid = pgaceSecurityLabelToSid(cache->ncontext);
+     }
+     return cache->nsid;
+ }
+
+ /*
+  * sepgsqlClientCreateContext
+  *   returns security context (string representation) of newly
+  *   created object. It is available for any kind of object
+  *   classes.
+  */
+ security_context_t
+ sepgsqlClientCreateContext(Oid tsid, security_class_t tclass)
+ {
+     avc_datum *cache = avc_lookup(tsid, tclass);
+
+     if (!cache)
+         cache = avc_make_entry(tsid, tclass);
+
+     return pstrdup(cache->ncontext);
+ }
+
+ /*
+  * sepgsql_shmem_init
+  *   attaches shared memory segment.
+  */
+ static void
+ sepgsql_shmem_init(void)
+ {
+     bool found;
+
+     selinux_state = ShmemInitStruct("SELinux policy state",
+                                     sepgsqlShmemSize(), &found);
+     if (!found)
+     {
+         int            enforcing = security_getenforce();
+
+         Assert(enforcing == 0 || enforcing == 1);
+
+         LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
+         selinux_state->version = 0;
+         selinux_state->enforcing = enforcing;
+         load_class_av_mapping();
+
+         LWLockRelease(SepgsqlAvcLock);
+     }
+ }
+
+ /*
+  * sepgsqlAvcInit
+  *   initialize local uAVC facility.
+  */
+ void
+ sepgsqlAvcInit(void)
+ {
+     /*
+      * local memory context
+      */
+     AvcMemCtx = AllocSetContextCreate(TopMemoryContext,
+                                       "SE-PostgreSQL userspace avc",
+                                       ALLOCSET_DEFAULT_MINSIZE,
+                                       ALLOCSET_DEFAULT_INITSIZE,
+                                       ALLOCSET_DEFAULT_MAXSIZE);
+     sepgsql_shmem_init();
+
+     /*
+      * reset local avc
+      */
+     sepgsql_avc_reset();
+ }
+
+ /*
+  * sepgsqlComputePermission
+  * sepgsqlComputeCreateContext
+  *
+  * The following two functions make a query to in-kernel SELinux
+  * without userspace caches, due to some reasons.
+  * The uAVC can cover most of cases, but some of corner cases are
+  * not suitable for uAVC structure, so we need uncached interfaces.
+  * For example, uAVC is unavailable when we tries to load a shared
+  * library module, because security context of the library does not
+  * have its security identifier, so we cannot put it on uAVC.
+  */
+ bool
+ sepgsqlComputePermission(const security_context_t scontext,
+                          const security_context_t tcontext,
+                          security_class_t tclass,
+                          access_vector_t perms,
+                          const char *objname)
+ {
+     security_context_t svcon, tvcon;
+     security_class_t e_tclass;
+     struct av_decision avd;
+     avc_datum cache;
+     bool rc;
+
+     svcon = (!security_check_context_raw(scontext)
+              ? scontext : sepgsqlGetUnlabeledContext());
+     tvcon = (!security_check_context_raw(tcontext)
+              ? tcontext : sepgsqlGetUnlabeledContext());
+
+     LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
+     e_tclass = trans_to_external_tclass(tclass);
+
+     if (security_compute_av_raw(svcon, tvcon, e_tclass, 0, &avd) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not compute an av_decision"
+                         " scontext=%s tcontext=%s tclass=%s",
+                         svcon, tvcon, security_class_to_string(e_tclass))));
+
+     cache.tclass = tclass;
+     cache.allowed = trans_to_internal_perms(e_tclass, avd.allowed, true);
+     cache.decided = trans_to_internal_perms(e_tclass, avd.decided, false);
+     cache.auditallow = trans_to_internal_perms(e_tclass, avd.auditallow, false);
+     cache.auditdeny = trans_to_internal_perms(e_tclass, avd.auditdeny, false);
+     LWLockRelease(SepgsqlAvcLock);
+
+     rc = avc_permission_common(&cache, perms, true, svcon, tvcon, objname);
+
+     if (svcon != scontext)
+         pfree(svcon);
+     if (tvcon != tcontext)
+         pfree(tvcon);
+
+     return rc;
+ }
+
+ security_context_t
+ sepgsqlComputeCreateContext(const security_context_t scontext,
+                             const security_context_t tcontext,
+                             security_class_t tclass)
+ {
+     security_context_t svcon, tvcon, nwcon, copy;
+     security_class_t e_tclass;
+
+     svcon = (!security_check_context_raw(scontext)
+              ? scontext : sepgsqlGetUnlabeledContext());
+     tvcon = (!security_check_context_raw(tcontext)
+              ? tcontext : sepgsqlGetUnlabeledContext());
+
+     LWLockAcquire(SepgsqlAvcLock, LW_SHARED);
+     e_tclass = trans_to_external_tclass(tclass);
+
+     if (security_compute_create_raw(svcon, tvcon, e_tclass, &nwcon) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not compute a default context"
+                         " scontext=%s tcontext=%s tclass=%s",
+                         scontext, tcontext, security_class_to_string(e_tclass))));
+
+     LWLockRelease(SepgsqlAvcLock);
+
+     if (svcon != scontext)
+         pfree(svcon);
+     if (tvcon != tcontext)
+         pfree(tvcon);
+
+     PG_TRY();
+     {
+         copy = pstrdup(nwcon);
+     }
+     PG_CATCH();
+     {
+         freecon(nwcon);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+
+     freecon(nwcon);
+
+     return copy;
+ }
+
+ /*
+  * SELinux state monitoring process
+  *
+  * This process is forked from postmaster to monitor the state of SELinux.
+  * SELinux can make a notifier message to userspace object manager via
+  * netlink socket. When it receives the message, it updates selinux_state
+  * structure assigned on shared memory region to make any instance reset
+  * its AVC soon.
+  */
+
+ static bool sepgsqlStateMonitorAlive = true;
+
+ static void
+ sepgsqlStateMonitorSIGHUP(SIGNAL_ARGS)
+ {
+     ereport(NOTICE,
+             (errcode(ERRCODE_SELINUX_INFO),
+              errmsg("SELinux: invalidate userspace avc")));
+     selinux_state->version = selinux_state->version + 1;
+ }
+
+ static int
+ sepgsqlStateMonitorMain()
+ {
+     char        buffer[2048];
+     struct sockaddr_nl addr;
+     socklen_t    addrlen;
+     struct nlmsghdr *nlh;
+     int            rc, nl_sockfd;
+
+     /*
+      * map shared memory segment
+      */
+     sepgsql_shmem_init();
+
+     /*
+      * setup the signal handler
+      */
+     pqinitmask();
+     pqsignal(SIGHUP, sepgsqlStateMonitorSIGHUP);
+     pqsignal(SIGINT, SIG_IGN);
+     pqsignal(SIGTERM, exit);
+     pqsignal(SIGQUIT, exit);
+     pqsignal(SIGUSR1, SIG_IGN);
+     pqsignal(SIGUSR2, SIG_IGN);
+     pqsignal(SIGCHLD, SIG_DFL);
+     PG_SETMASK(&UnBlockSig);
+
+     ereport(NOTICE,
+             (errcode(ERRCODE_SELINUX_INFO),
+              errmsg("SELinux: policy state monitor process (pid: %u)",
+                     getpid())));
+     /*
+      * open netlink socket
+      */
+     nl_sockfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SELINUX);
+     if (nl_sockfd < 0)
+     {
+         ereport(NOTICE,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not open netlink socket")));
+         return 1;
+     }
+     memset(&addr, 0, sizeof(addr));
+     addr.nl_family = AF_NETLINK;
+     addr.nl_groups = SELNL_GRP_AVC;
+     if (bind(nl_sockfd, (struct sockaddr *) &addr, sizeof(addr)))
+     {
+         ereport(NOTICE,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not bind netlink socket")));
+         return 1;
+     }
+
+     /*
+      * waiting loop
+      */
+     while (sepgsqlStateMonitorAlive)
+     {
+         addrlen = sizeof(addr);
+         rc = recvfrom(nl_sockfd, buffer, sizeof(buffer), 0,
+                       (struct sockaddr *) &addr, &addrlen);
+         if (rc < 0)
+         {
+             if (errno == EINTR)
+                 continue;
+
+             ereport(NOTICE,
+                     (errcode(ERRCODE_SELINUX_ERROR),
+                      errmsg("SELinux: error on netlink recvfrom(): %s",
+                             strerror(errno))));
+             return 1;
+         }
+
+         if (addrlen != sizeof(addr))
+         {
+             ereport(NOTICE,
+                     (errcode(ERRCODE_SELINUX_ERROR),
+                      errmsg("SELinux: netlink address truncated (len=%d)",
+                             addrlen)));
+             return 1;
+         }
+
+         if (addr.nl_pid)
+         {
+             ereport(NOTICE,
+                     (errcode(ERRCODE_SELINUX_ERROR),
+                      errmsg("SELinux: netlink received spoofed packet from: %u",
+                             addr.nl_pid)));
+             continue;
+         }
+
+         if (rc == 0)
+         {
+             ereport(NOTICE,
+                     (errcode(ERRCODE_SELINUX_ERROR),
+                      errmsg("SELinux: netlink received EOF")));
+             return 1;
+         }
+
+         nlh = (struct nlmsghdr *) buffer;
+         if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned int) rc)
+         {
+             ereport(NOTICE,
+                     (errcode(ERRCODE_SELINUX_ERROR),
+                      errmsg("SELinux: netlink incomplete message")));
+             return 1;
+         }
+
+         switch (nlh->nlmsg_type)
+         {
+             case SELNL_MSG_SETENFORCE:
+                 {
+                     struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
+
+                     ereport(NOTICE,
+                             (errcode(ERRCODE_SELINUX_INFO),
+                              errmsg("SELinux: setenforce notifier"
+                                     " (enforcing=%d)", msg->val)));
+
+                     LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
+                     load_class_av_mapping();
+
+                     /*
+                      * userspace avc invalidation
+                      */
+                     selinux_state->version = selinux_state->version + 1;
+                     selinux_state->enforcing = msg->val ? true : false;
+
+                     LWLockRelease(SepgsqlAvcLock);
+                     break;
+                 }
+             case SELNL_MSG_POLICYLOAD:
+                 {
+                     struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
+
+                     ereport(NOTICE,
+                             (errcode(ERRCODE_SELINUX_INFO),
+                              errmsg("policyload notifier (seqno=%d)",
+                                     msg->seqno)));
+
+                     LWLockAcquire(SepgsqlAvcLock, LW_EXCLUSIVE);
+                     load_class_av_mapping();
+                     /*
+                      * userspace avc invalidation
+                      */
+                     selinux_state->version = selinux_state->version + 1;
+
+                     LWLockRelease(SepgsqlAvcLock);
+                     break;
+                 }
+             case NLMSG_ERROR:
+                 {
+                     struct nlmsgerr *err = NLMSG_DATA(nlh);
+
+                     if (err->error == 0)
+                         break;
+
+                     ereport(NOTICE,
+                             (errcode(ERRCODE_SELINUX_ERROR),
+                              errmsg("SELinux: netlink error: %s",
+                                     strerror(-err->error))));
+                     return 1;
+                 }
+             default:
+                 ereport(NOTICE,
+                         (errcode(ERRCODE_SELINUX_ERROR),
+                          errmsg("netlink unknown message type (%d)",
+                                 nlh->nlmsg_type)));
+                 return 1;
+         }
+     }
+     return 0;
+ }
+
+ pid_t
+ sepgsqlStartupWorkerProcess(void)
+ {
+     pid_t        chld;
+
+     chld = fork();
+     if (chld == 0)
+     {
+         ClosePostmasterPorts(false);
+
+         on_exit_reset();
+
+         exit(sepgsqlStateMonitorMain());
+     }
+     else if (chld > 0)
+         return chld;
+
+     return (pid_t) 0;
+ }
diff -Nrpc base/src/backend/security/sepgsql/core.c sepgsql/src/backend/security/sepgsql/core.c
*** base/src/backend/security/sepgsql/core.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/sepgsql/core.c    Sat Jan 24 22:42:56 2009
***************
*** 0 ****
--- 1,623 ----
+ /*
+  * src/backend/security/sepgsql/core.c
+  *     SE-PostgreSQL core facilities
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+
+ #include "catalog/pg_database.h"
+ #include "catalog/pg_security.h"
+ #include "libpq/libpq.h"
+ #include "miscadmin.h"
+ #include "security/pgace.h"
+ #include "utils/builtins.h"
+ #include "utils/syscache.h"
+ #include <selinux/context.h>
+
+ int sepostgresql_mode;
+
+ static security_context_t serverContext = NULL;
+ static security_context_t clientContext = NULL;
+ static security_context_t unlabeledContext = NULL;
+
+ const security_context_t
+ sepgsqlGetServerContext(void)
+ {
+     Assert(serverContext != NULL);
+     return serverContext;
+ }
+
+ const security_context_t
+ sepgsqlGetClientContext(void)
+ {
+     Assert(clientContext != NULL);
+     return clientContext;
+ }
+
+ const security_context_t
+ sepgsqlGetDatabaseContext(void)
+ {
+     security_context_t result;
+
+     if (IsBootstrapProcessingMode())
+     {
+         static security_context_t dbcontext = NULL;
+
+         if (!dbcontext)
+         {
+             if (security_compute_create_raw(sepgsqlGetClientContext(),
+                                             sepgsqlGetClientContext(),
+                                             SECCLASS_DB_DATABASE,
+                                             &dbcontext) < 0)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SELINUX_ERROR),
+                          errmsg("SELinux: could not get database context")));
+         }
+         result = pstrdup(dbcontext);
+     }
+     else
+     {
+         HeapTuple tuple;
+
+         tuple = SearchSysCache(DATABASEOID,
+                                ObjectIdGetDatum(MyDatabaseId),
+                                0, 0, 0);
+         if (!HeapTupleIsValid(tuple))
+             elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId);
+
+         result = pgaceLookupSecurityLabel(HeapTupleGetSecLabel(tuple));
+         if (!result || !pgaceCheckValidSecurityLabel(result))
+             result = pgaceUnlabeledSecurityLabel();
+
+         ReleaseSysCache(tuple);
+     }
+
+     return result;
+ }
+
+ Oid
+ sepgsqlGetDatabaseSecurityId(void)
+ {
+     Oid sid;
+
+     if (IsBootstrapProcessingMode())
+     {
+         security_context_t dcontext
+             = sepgsqlGetDatabaseContext();
+
+         sid = pgaceSecurityLabelToSid(dcontext);
+     }
+     else
+     {
+         HeapTuple tuple;
+
+         tuple = SearchSysCache(DATABASEOID,
+                                ObjectIdGetDatum(MyDatabaseId),
+                                0, 0, 0);
+         if (!HeapTupleIsValid(tuple))
+             elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId);
+
+         sid = HeapTupleGetSecLabel(tuple);
+
+         ReleaseSysCache(tuple);
+     }
+
+     return sid;
+ }
+
+ const security_context_t
+ sepgsqlGetUnlabeledContext(void)
+ {
+     if (unlabeledContext)
+         return unlabeledContext;
+
+     if (security_get_initial_context_raw("unlabeled", &unlabeledContext) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not get unlabeled context")));
+
+     return unlabeledContext;
+ }
+
+ const security_context_t
+ sepgsqlSwitchClientContext(security_context_t new_context)
+ {
+     security_context_t original_context = clientContext;
+
+     clientContext = new_context;
+
+     sepgsqlAvcSwitchClientContext(new_context);
+
+     return original_context;
+ }
+
+ static void
+ initContexts(void)
+ {
+     /*
+      * server context
+      */
+     if (getcon_raw(&serverContext) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not get server process context")));
+
+     /*
+      * client context
+      */
+     if (!MyProcPort)
+     {
+         /*
+          * When the proces is not invoked as a backend of clietnt,
+          * it works as a server process and as a client process
+          * in same time.
+          */
+         clientContext = serverContext;
+     }
+     else
+     {
+         if (getpeercon_raw(MyProcPort->sock, &clientContext) < 0)
+         {
+             /*
+              * fallbacked security context
+              *
+              * When getpeercon() API does not obtain the context of
+              * peer process, SEPGSQL_FALLBACK_CONTEXT environment
+              * variable is used as an alternative security context
+              * of the peer.
+              *
+              * getpeercon() needs the following condition to fail:
+              * - Connection come from remote host,
+              * - and, there is no labeled ipsec configuration between
+              *   localhost and remote host.
+              * - and, there is no static fallbacked context configuration
+              *   for the remote host.
+              */
+             char       *fallback = getenv("SEPGSQL_FALLBACK_CONTEXT");
+
+             if (!fallback)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SELINUX_ERROR),
+                          errmsg
+                          ("SELinux: could not get client process context")));
+
+             if (security_check_context(fallback) < 0
+                 || selinux_trans_to_raw_context(fallback, &clientContext) < 0)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SELINUX_ERROR),
+                          errmsg("SELinux: %s is not a valid context",
+                                 fallback)));
+         }
+     }
+ }
+
+ /*
+  * sepgsqlInitialize
+  *
+  * It initializes SE-PostgreSQL itself including assignment of shared
+  * memory segment, reset of AVC, obtaining the client/server security
+  * context and checks whether the client can access the required database,
+  * or not.
+  */
+ void
+ sepgsqlInitialize(bool bootstrap)
+ {
+     char       *dbname;
+
+     initContexts();
+
+     sepgsqlAvcInit();
+
+     /*
+      * check db_database:{ access }
+      */
+     if (IsBootstrapProcessingMode())
+         dbname = "template1";
+     else
+     {
+         Form_pg_database dbForm;
+         HeapTuple    tuple;
+
+         tuple = SearchSysCache(DATABASEOID,
+                                ObjectIdGetDatum(MyDatabaseId), 0, 0, 0);
+         if (!HeapTupleIsValid(tuple))
+             elog(ERROR, "SELinux: cache lookup failed for database %u",
+                  MyDatabaseId);
+         dbForm = (Form_pg_database) GETSTRUCT(tuple);
+
+         dbname = pstrdup(NameStr(dbForm->datname));
+
+         ReleaseSysCache(tuple);
+     }
+
+     sepgsqlComputePermission(sepgsqlGetClientContext(),
+                              sepgsqlGetDatabaseContext(),
+                              SECCLASS_DB_DATABASE,
+                              DB_DATABASE__ACCESS,
+                              dbname);
+ }
+
+ /*
+  * sepgsqlIsEnabled
+  *
+  * This function returns the state of SE-PostgreSQL when PGACE hooks
+  * are invoked, to prevent to call sepgsqlXXXX() functions when
+  * SE-PostgreSQL is disabled.
+  *
+  * We can config the state of SE-PostgreSQL in $PGDATA/postgresql.conf.
+  * The GUC option "sepostgresql" can have the following four parameter.
+  *
+  * - default    : It always follows the in-kernel SELinux state. When it
+  *                works in Enforcing mode, SE-PostgreSQL also works in
+  *                Enforcing mode. Changes of in-kernel state are delivered
+  *                to userspace SE-PostgreSQL soon, and SELinux state
+  *                monitoring process updates it rapidly.
+  * - enforcing  : It always works in Enforcing mode. In-kernel SELinux
+  *                has to be enabled.
+  * - permissive : It always works in Permissive mode. In-kernel SELinux
+  *                has to be enabled.
+  * - disabled   : It disables SE-PostgreSQL feature. It works as if
+  *                original PostgreSQL
+  */
+ bool
+ sepgsqlIsEnabled(void)
+ {
+     static int    enabled = -1;
+
+     if (enabled < 0)
+     {
+         if (sepostgresql_mode == SEPGSQL_MODE_DISABLED)
+             enabled = 0;
+         else
+         {
+             enabled = is_selinux_enabled();
+             if (enabled == 0    /* in-kernel SELinux is disabled */
+                 && sepostgresql_mode != SEPGSQL_MODE_DEFAULT)
+             {
+                 ereport(FATAL,
+                         (errcode(ERRCODE_SELINUX_ERROR),
+                          errmsg("SELinux: disabled in kernel, but sepostgresql = %s",
+                                 SEPGSQL_MODE_ENFORCING ? "enforcing" : "permissive")));
+             }
+         }
+     }
+
+     return enabled > 0 ? true : false;
+ }
+
+ /*
+  * sepgsql_getcon(void)
+  *
+  * It returns security context of client
+  */
+ Datum
+ sepgsql_getcon(PG_FUNCTION_ARGS)
+ {
+     security_context_t context;
+     Datum        labelTxt;
+
+     if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled())
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: disabled now")));
+
+     if (selinux_raw_to_trans_context(clientContext, &context) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not translate mls label")));
+     PG_TRY();
+     {
+         labelTxt = CStringGetTextDatum(context);
+     }
+     PG_CATCH();
+     {
+         freecon(context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(context);
+
+     PG_RETURN_DATUM(labelTxt);
+ }
+
+ /*
+  * sepgsql_getcon(void)
+  *
+  * It returns security context of server process
+  */
+ Datum
+ sepgsql_getservcon(PG_FUNCTION_ARGS)
+ {
+     security_context_t context;
+     Datum        labelTxt;
+
+     if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled())
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: disabled now")));
+
+     if (selinux_raw_to_trans_context(serverContext, &context) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not translate mls label")));
+     PG_TRY();
+     {
+         labelTxt = CStringGetTextDatum(context);
+     }
+     PG_CATCH();
+     {
+         freecon(context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(context);
+
+     PG_RETURN_DATUM(labelTxt);
+ }
+
+ static void
+ parse_to_context(security_context_t context,
+                  char **user, char **role, char **type, char **range)
+ {
+     security_context_t raw_context;
+
+     if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled())
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: disabled now")));
+
+     if (selinux_trans_to_raw_context(context, &raw_context) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not translate mls label")));
+     PG_TRY();
+     {
+         char       *tmp;
+
+         tmp = pstrdup(strtok(raw_context, ":"));
+         if (user)
+             *user = tmp;
+         tmp = pstrdup(strtok(NULL, ":"));
+         if (role)
+             *role = tmp;
+         tmp = pstrdup(strtok(NULL, ":"));
+         if (type)
+             *type = tmp;
+         if (is_selinux_mls_enabled())
+         {
+             tmp = pstrdup(strtok(NULL, "\0"));
+             if (range)
+                 *range = tmp;
+         }
+         else if (range)
+             *range = NULL;
+     }
+     PG_CATCH();
+     {
+         freecon(raw_context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(raw_context);
+ }
+
+ /*
+  * text sepgsql_get_user(text)
+  *
+  * It picks up the USER field of given security context.
+  */
+ Datum
+ sepgsql_get_user(PG_FUNCTION_ARGS)
+ {
+     char       *user;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      &user, NULL, NULL, NULL);
+     PG_RETURN_TEXT_P(CStringGetTextDatum(user));
+ }
+
+ /*
+  * text sepgsql_set_user(text, text)
+  *
+  * It replaces the USER field of given security context by the second argument.
+  */
+ Datum
+ sepgsql_set_user(PG_FUNCTION_ARGS)
+ {
+     char       *user, *role, *type, *range;
+     char        buffer[1024];
+     security_context_t newcon;
+     Datum        result;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      &user, &role, &type, &range);
+     if (range)
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
+                  TextDatumGetCString(PG_GETARG_TEXT_P(1)), role, type, range);
+     else
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s",
+                  TextDatumGetCString(PG_GETARG_TEXT_P(1)), role, type);
+     if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not set a new user")));
+     PG_TRY();
+     {
+         result = CStringGetTextDatum(newcon);
+     }
+     PG_CATCH();
+     {
+         freecon(newcon);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(newcon);
+
+     PG_RETURN_DATUM(result);
+ }
+
+ /*
+  * text sepgsql_get_role(text)
+  *
+  * It picks up the ROLE field of given security context.
+  */
+ Datum
+ sepgsql_get_role(PG_FUNCTION_ARGS)
+ {
+     char       *role;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      NULL, &role, NULL, NULL);
+     PG_RETURN_TEXT_P(CStringGetTextDatum(role));
+ }
+
+ /*
+  * text sepgsql_set_user(text, text)
+  *
+  * It replaces the ROLE field of given security context by the second argument.
+  */
+ Datum
+ sepgsql_set_role(PG_FUNCTION_ARGS)
+ {
+     char       *user, *role, *type, *range;
+     char        buffer[1024];
+     security_context_t newcon;
+     Datum        result;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      &user, &role, &type, &range);
+     if (range)
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
+                  user, TextDatumGetCString(PG_GETARG_TEXT_P(1)), type, range);
+     else
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s",
+                  user, TextDatumGetCString(PG_GETARG_TEXT_P(1)), type);
+     if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not set a new role")));
+     PG_TRY();
+     {
+         result = CStringGetTextDatum(newcon);
+     }
+     PG_CATCH();
+     {
+         freecon(newcon);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(newcon);
+
+     PG_RETURN_DATUM(result);
+ }
+
+ /*
+  * text sepgsql_get_type(text)
+  *
+  * It picks up the TYPE field of given security context.
+  */
+ Datum
+ sepgsql_get_type(PG_FUNCTION_ARGS)
+ {
+     char       *type;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      NULL, NULL, &type, NULL);
+     PG_RETURN_TEXT_P(CStringGetTextDatum(type));
+ }
+
+ /*
+  * text sepgsql_set_user(text, text)
+  *
+  * It replaces the TYPE field of given security context by the second argument.
+  */
+ Datum
+ sepgsql_set_type(PG_FUNCTION_ARGS)
+ {
+     char       *user, *role, *type, *range;
+     char        buffer[1024];
+     security_context_t newcon;
+     Datum        result;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      &user, &role, &type, &range);
+     if (range)
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
+                  user, role, TextDatumGetCString(PG_GETARG_TEXT_P(1)), range);
+     else
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s",
+                  user, role, TextDatumGetCString(PG_GETARG_TEXT_P(1)));
+     if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not set a new type")));
+     PG_TRY();
+     {
+         result = CStringGetTextDatum(newcon);
+     }
+     PG_CATCH();
+     {
+         freecon(newcon);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(newcon);
+
+     PG_RETURN_DATUM(result);
+ }
+
+ /*
+  * text sepgsql_get_range(text)
+  *
+  * It picks up the RANGE field of given security context.
+  */
+ Datum
+ sepgsql_get_range(PG_FUNCTION_ARGS)
+ {
+     char       *range;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      NULL, NULL, NULL, &range);
+     PG_RETURN_TEXT_P(CStringGetTextDatum(range));
+ }
+
+ /*
+  * text sepgsql_set_user(text, text)
+  *
+  * It replaces the RANGE field of given security context by the second argument.
+  */
+ Datum
+ sepgsql_set_range(PG_FUNCTION_ARGS)
+ {
+     char       *user, *role, *type, *range;
+     char        buffer[1024];
+     security_context_t newcon;
+     Datum        result;
+
+     parse_to_context(TextDatumGetCString(PG_GETARG_TEXT_P(0)),
+                      &user, &role, &type, &range);
+     if (range)
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s:%s",
+                  user, role, type, TextDatumGetCString(PG_GETARG_TEXT_P(1)));
+     else
+         snprintf(buffer, sizeof(buffer), "%s:%s:%s", user, role, type);
+     if (selinux_raw_to_trans_context((security_context_t) buffer, &newcon) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not set a new range")));
+     PG_TRY();
+     {
+         result = CStringGetTextDatum(newcon);
+     }
+     PG_CATCH();
+     {
+         freecon(newcon);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(newcon);
+
+     PG_RETURN_DATUM(result);
+ }
diff -Nrpc base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/security/sepgsql/hooks.c
*** base/src/backend/security/sepgsql/hooks.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/sepgsql/hooks.c    Thu Jan 22 10:39:45 2009
***************
*** 0 ****
--- 1,1019 ----
+ /*
+  * src/backend/security/sepgsql/hooks.c
+  *      Implementations of PGACE framework in SE-PostgreSQL
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+
+ #include "access/heapam.h"
+ #include "access/genam.h"
+ #include "access/skey.h"
+ #include "access/sysattr.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_aggregate.h"
+ #include "catalog/pg_database.h"
+ #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_proc.h"
+ #include "catalog/pg_security.h"
+ #include "miscadmin.h"
+ #include "nodes/makefuncs.h"
+ #include "security/pgace.h"
+ #include "storage/bufmgr.h"
+ #include "utils/fmgroids.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+ /*******************************************************************************
+  * Extended SQL statement hooks
+  *******************************************************************************/
+ bool
+ sepgsqlIsGramSecurityItem(DefElem *defel)
+ {
+     Assert(IsA(defel, DefElem));
+
+     if (defel->defname &&
+         strcmp(defel->defname, SecurityLabelAttributeName) == 0)
+         return true;
+
+     return false;
+ }
+
+ static void
+ putExplicitContext(HeapTuple tuple, DefElem *defel)
+ {
+     if (defel)
+     {
+         Oid sid  = pgaceSecurityLabelToSid(strVal(defel->arg));
+
+         HeapTupleSetSecLabel(tuple, sid);
+     }
+ }
+
+ void
+ sepgsqlGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ void
+ sepgsqlGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ void
+ sepgsqlGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ void
+ sepgsqlGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ void
+ sepgsqlGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ void
+ sepgsqlGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ void
+ sepgsqlGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ void
+ sepgsqlGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel)
+ {
+     putExplicitContext(tuple, defel);
+ }
+
+ /*******************************************************************************
+  * DATABASE object related hooks
+  *******************************************************************************/
+
+ void
+ sepgsqlGetDatabaseParam(const char *name)
+ {
+     HeapTuple    tuple;
+     const char *audit_name;
+
+     tuple = SearchSysCache(DATABASEOID,
+                            ObjectIdGetDatum(MyDatabaseId), 0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "SELinux: cache lookup failed for database %u",
+              MyDatabaseId);
+
+     audit_name = sepgsqlTupleName(DatabaseRelationId, tuple);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                SECCLASS_DB_DATABASE,
+                                DB_DATABASE__GET_PARAM,
+                                audit_name);
+     ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsqlSetDatabaseParam(const char *name, char *argstring)
+ {
+     HeapTuple    tuple;
+     const char *audit_name;
+
+     tuple = SearchSysCache(DATABASEOID,
+                            ObjectIdGetDatum(MyDatabaseId), 0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "SELinux: cache lookup failed for database %u",
+              MyDatabaseId);
+
+     audit_name = sepgsqlTupleName(DatabaseRelationId, tuple);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                SECCLASS_DB_DATABASE,
+                                DB_DATABASE__SET_PARAM,
+                                audit_name);
+     ReleaseSysCache(tuple);
+ }
+
+ /*******************************************************************************
+  * RELATION(Table)/ATTRIBTUE(column) object related hooks
+  *******************************************************************************/
+ void
+ sepgsqlLockTable(Oid relid)
+ {
+     HeapTuple    tuple;
+
+     tuple = SearchSysCache(RELOID,
+                            ObjectIdGetDatum(relid),
+                            0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "SELinux: cache lookup failed for relation %u", relid);
+
+     if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
+     {
+         const char *audit_name
+             = sepgsqlTupleName(RelationRelationId, tuple);
+         sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                    SECCLASS_DB_TABLE,
+                                    DB_TABLE__LOCK,
+                                    audit_name);
+     }
+     ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsqlExecTruncate(List *trunc_rels)
+ {
+     ListCell *l;
+
+     foreach (l, trunc_rels)
+     {
+         const char *audit_name;
+         HeapTuple tuple;
+         HeapScanDesc scan;
+         Relation rel = (Relation) lfirst(l);
+
+         if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
+             continue;
+
+         /*
+          * check db_table:{delete}
+          */
+         tuple = SearchSysCache(RELOID,
+                                ObjectIdGetDatum(RelationGetRelid(rel)),
+                                0, 0, 0);
+         if (!HeapTupleIsValid(tuple))
+             elog(ERROR, "SELinux: cache lookup failed for relation %u",
+                  RelationGetRelid(rel));
+
+         audit_name = sepgsqlTupleName(RelationRelationId, tuple);
+         sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                    SECCLASS_DB_TABLE,
+                                    DB_TABLE__DELETE,
+                                    audit_name);
+         ReleaseSysCache(tuple);
+
+         /*
+          * check db_tuple:{delete}
+          */
+         scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
+
+         while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+         {
+             sepgsqlCheckTuplePerms(rel, tuple, NULL,
+                                    SEPGSQL_PERMS_DELETE, true);
+         }
+         heap_endscan(scan);
+     }
+ }
+
+ /*******************************************************************************
+  * PROCEDURE related hooks
+  *******************************************************************************/
+
+ typedef struct
+ {
+     PGFunction            fn_addr;
+     security_context_t    fn_con;
+ } sepgsql_fn_info;
+
+ static Datum
+ invokeTrustedProcedure(PG_FUNCTION_ARGS)
+ {
+     sepgsql_fn_info *sefinfo = fcinfo->flinfo->fn_pgaceItem;
+     security_context_t orig_context;
+     Datum        retval;
+
+     /*
+      * set new domain
+      */
+     orig_context = sepgsqlSwitchClientContext(sefinfo->fn_con);
+
+     PG_TRY();
+     {
+         retval = sefinfo->fn_addr(fcinfo);
+     }
+     PG_CATCH();
+     {
+         sepgsqlSwitchClientContext(orig_context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     sepgsqlSwitchClientContext(orig_context);
+
+     return retval;
+ }
+
+ void
+ sepgsqlCallFunction(FmgrInfo *finfo)
+ {
+     MemoryContext        oldctx;
+     HeapTuple            tuple;
+     security_context_t    newcon;
+     access_vector_t        perms = DB_PROCEDURE__EXECUTE;
+     const char           *audit_name;
+
+     if (IsBootstrapProcessingMode())
+         return;        /* under initialization of pg_proc */
+
+     tuple = SearchSysCache(PROCOID,
+                            ObjectIdGetDatum(finfo->fn_oid),
+                            0, 0, 0);
+     Assert(HeapTupleIsValid(tuple));
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "SELinux: cache lookup failed for procedure %u", finfo->fn_oid);
+
+     oldctx = MemoryContextSwitchTo(finfo->fn_mcxt);
+     /*
+      * check trusted procedure
+      */
+     newcon = sepgsqlClientCreateContext(HeapTupleGetSecLabel(tuple),
+                                         SECCLASS_PROCESS);
+     if (strcmp(newcon, sepgsqlGetClientContext()) != 0)
+     {
+         sepgsql_fn_info *sefinfo
+             = palloc0(sizeof(sepgsql_fn_info));
+
+         sefinfo->fn_addr = finfo->fn_addr;
+         sefinfo->fn_con = newcon;
+         finfo->fn_addr = invokeTrustedProcedure;
+         finfo->fn_pgaceItem = sefinfo;
+
+         perms |= DB_PROCEDURE__ENTRYPOINT;
+     }
+     else
+         pfree(newcon);
+
+     MemoryContextSwitchTo(oldctx);
+
+     audit_name = sepgsqlTupleName(ProcedureRelationId, tuple);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                SECCLASS_DB_PROCEDURE,
+                                perms,
+                                audit_name);
+     ReleaseSysCache(tuple);
+ }
+
+ void
+ sepgsqlCallAggFunction(HeapTuple aggTuple)
+ {
+     Form_pg_aggregate aggForm
+         = (Form_pg_aggregate) GETSTRUCT(aggTuple);
+     HeapTuple tuple;
+     const char *audit_name;
+
+     /* check pg_proc.oid = pg_aggregate.aggfnoid */
+     tuple = SearchSysCache(PROCOID,
+                            ObjectIdGetDatum(aggForm->aggfnoid),
+                            0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "SELinux: cache lookup failed for procedure %u",
+              aggForm->aggfnoid);
+
+     audit_name = sepgsqlTupleName(ProcedureRelationId, tuple);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                SECCLASS_DB_PROCEDURE,
+                                DB_PROCEDURE__EXECUTE,
+                                audit_name);
+     ReleaseSysCache(tuple);
+ }
+
+ bool
+ sepgsqlCallTriggerFunction(TriggerData *tgdata)
+ {
+     Relation    rel = tgdata->tg_relation;
+     HeapTuple    newtup = NULL;
+     HeapTuple    oldtup = NULL;
+
+     /*
+      * We don't need to check tuple permissions for
+      * statement triggers
+      */
+     if (TRIGGER_FIRED_FOR_STATEMENT(tgdata->tg_event))
+         return true;
+
+     if (TRIGGER_FIRED_BY_INSERT(tgdata->tg_event))
+     {
+         if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
+             newtup = tgdata->tg_trigtuple;
+     }
+     else if (TRIGGER_FIRED_BY_UPDATE(tgdata->tg_event))
+     {
+         oldtup = tgdata->tg_trigtuple;
+         if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
+         {
+             Oid securityId = HeapTupleGetSecLabel(tgdata->tg_newtuple);
+
+             if (HeapTupleGetSecLabel(oldtup) != securityId)
+                 newtup = tgdata->tg_newtuple;
+         }
+     }
+     else if (TRIGGER_FIRED_BY_DELETE(tgdata->tg_event))
+     {
+         if (TRIGGER_FIRED_AFTER(tgdata->tg_event))
+             oldtup = tgdata->tg_trigtuple;
+     }
+     else
+     {
+         elog(ERROR, "SELinux: unexpected trigger event type (%u)",
+              tgdata->tg_event);
+     }
+     if (oldtup && !sepgsqlCheckTuplePerms(rel, oldtup, NULL,
+                                           SEPGSQL_PERMS_SELECT, false))
+         return false;
+     if (newtup && !sepgsqlCheckTuplePerms(rel, newtup, NULL,
+                                           SEPGSQL_PERMS_SELECT, false))
+         return false;
+
+     return true;
+ }
+
+ bool sepgsqlAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple)
+ {
+     security_context_t    newcon;
+     const char *audit_name;
+
+     /*
+      * If function is defined as trusted procedure, we always should
+      * not allow it to be inlined, and actual permission checks are
+      * done later phase.
+      */
+     newcon = sepgsqlClientCreateContext(HeapTupleGetSecLabel(func_tuple),
+                                         SECCLASS_PROCESS);
+     if (strcmp(newcon, sepgsqlGetClientContext()) != 0)
+         return false;
+
+     audit_name = sepgsqlTupleName(ProcedureRelationId, func_tuple);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(func_tuple),
+                                SECCLASS_DB_PROCEDURE,
+                                DB_PROCEDURE__EXECUTE,
+                                audit_name);
+     return true;
+ }
+
+ /*******************************************************************************
+  * LOAD shared library module hook
+  *******************************************************************************/
+ void
+ sepgsqlLoadSharedModule(const char *filename)
+ {
+     security_context_t filecon;
+
+     if (getfilecon_raw(filename, &filecon) < 0)
+         ereport(ERROR,
+                 (errcode_for_file_access(),
+                  errmsg("could not access file \"%s\": %m", filename)));
+     PG_TRY();
+     {
+         sepgsqlComputePermission(sepgsqlGetDatabaseContext(),
+                                  filecon,
+                                  SECCLASS_DB_DATABASE,
+                                  DB_DATABASE__LOAD_MODULE,
+                                  filename);
+     }
+     PG_CATCH();
+     {
+         freecon(filecon);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(filecon);
+ }
+
+ /*******************************************************************************
+  * Binary Large Object hooks
+  *******************************************************************************/
+
+ void
+ sepgsqlLargeObjectCreate(Relation rel, HeapTuple tuple)
+ {
+     const char *audit_name;
+
+     sepgsqlSetDefaultContext(rel, tuple);
+
+     audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                SECCLASS_DB_BLOB,
+                                DB_BLOB__CREATE,
+                                audit_name);
+ }
+
+ void
+ sepgsqlLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem)
+ {
+     Oid            security_id = HeapTupleGetSecLabel(tuple);
+     List       *okList = (List *) (*pgaceItem);
+     ListCell   *l;
+     const char *audit_name;
+
+     foreach (l, okList)
+     {
+         if (security_id == lfirst_oid(l))
+             return;        /* already allowed */
+     }
+
+     audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple);
+     sepgsqlClientHasPermission(security_id,
+                                SECCLASS_DB_BLOB,
+                                DB_BLOB__DROP,
+                                audit_name);
+
+     *pgaceItem = lappend_oid(okList, security_id);
+ }
+
+ static void
+ checkLargeObjectPages(Oid loid, Snapshot snapshot,
+                       int32 start_pageno, int32 end_pageno,
+                       access_vector_t perms)
+ {
+     Relation        rel;
+     HeapTuple        tuple;
+     SysScanDesc        sd;
+     ScanKeyData        skey[2];
+     List           *okList = NIL;
+
+     rel = heap_open(LargeObjectRelationId, AccessShareLock);
+
+     ScanKeyInit(&skey[0],
+                 Anum_pg_largeobject_loid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(loid));
+
+     if (start_pageno <= 0)
+         sd = systable_beginscan(rel, LargeObjectLOidPNIndexId,
+                                 true, snapshot, 1, skey);
+     else
+     {
+         ScanKeyInit(&skey[1],
+                     Anum_pg_largeobject_pageno,
+                     BTGreaterEqualStrategyNumber, F_INT4GE,
+                     Int32GetDatum(start_pageno));
+
+         sd = systable_beginscan(rel, LargeObjectLOidPNIndexId,
+                                 true, snapshot, 2, skey);
+     }
+
+     while ((tuple = systable_getnext(sd)) != NULL)
+     {
+         Form_pg_largeobject loForm
+             = (Form_pg_largeobject) GETSTRUCT(tuple);
+         Oid            security_id;
+         ListCell    *l;
+         const char  *audit_name;
+
+         if (end_pageno >= 0 && loForm->pageno > end_pageno)
+             break;
+
+         security_id = HeapTupleGetSecLabel(tuple);
+
+         foreach (l, okList)
+         {
+             if (security_id == lfirst_oid(l))
+                 goto skip;
+         }
+         okList = lappend_oid(okList, security_id);
+
+         audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple);
+         sepgsqlClientHasPermission(security_id,
+                                    SECCLASS_DB_BLOB,
+                                    perms,
+                                    audit_name);
+     skip:
+         ;
+     }
+     systable_endscan(sd);
+
+     list_free(okList);
+
+     heap_close(rel, NoLock);
+ }
+
+ void
+ sepgsqlLargeObjectRead(LargeObjectDesc *lodesc, int32 length)
+ {
+     int32 start_pageno    = lodesc->offset / LOBLKSIZE;
+     int32 end_pageno    = (lodesc->offset + length + LOBLKSIZE - 1) / LOBLKSIZE;
+
+     checkLargeObjectPages(lodesc->id, lodesc->snapshot,
+                           start_pageno, end_pageno, DB_BLOB__READ);
+ }
+
+ void
+ sepgsqlLargeObjectWrite(LargeObjectDesc *lodesc, int32 length)
+ {
+     int32 start_pageno    = lodesc->offset / LOBLKSIZE;
+     int32 end_pageno    = (lodesc->offset + length + LOBLKSIZE - 1) / LOBLKSIZE;
+
+     checkLargeObjectPages(lodesc->id, lodesc->snapshot,
+                           start_pageno, end_pageno, DB_BLOB__WRITE);
+ }
+
+ void
+ sepgsqlLargeObjectTruncate(LargeObjectDesc *lodesc, int32 offset)
+ {
+     int32 start_pageno    = lodesc->offset / LOBLKSIZE;
+
+     checkLargeObjectPages(lodesc->id, lodesc->snapshot,
+                           start_pageno, -1, DB_BLOB__WRITE);
+ }
+
+ void
+ sepgsqlLargeObjectImport(Oid loid, int fdesc, const char *filename)
+ {
+     security_context_t    tcontext;
+     security_class_t tclass
+         = sepgsqlFileObjectClass(fdesc, filename);
+
+     if (fgetfilecon_raw(fdesc, &tcontext) < 0)
+         ereport(ERROR,
+                 (errcode_for_file_access(),
+                  errmsg("could not get security context \"%s\": %m", filename)));
+     PG_TRY();
+     {
+         sepgsqlComputePermission(sepgsqlGetClientContext(),
+                                  tcontext,
+                                  tclass,
+                                  FILE__READ,
+                                  filename);
+     }
+     PG_CATCH();
+     {
+         freecon(tcontext);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(tcontext);
+
+     checkLargeObjectPages(loid, SnapshotNow, -1, -1,
+                           DB_BLOB__WRITE | DB_BLOB__IMPORT);
+ }
+
+ void
+ sepgsqlLargeObjectExport(Oid loid, int fdesc, const char *filename)
+ {
+     security_context_t    tcontext;
+     security_class_t tclass
+         = sepgsqlFileObjectClass(fdesc, filename);
+
+     if (fgetfilecon_raw(fdesc, &tcontext) < 0)
+         ereport(ERROR,
+                 (errcode_for_file_access(),
+                  errmsg("could not security context \"%s\": %m", filename)));
+     PG_TRY();
+     {
+         sepgsqlComputePermission(sepgsqlGetClientContext(),
+                                  tcontext,
+                                  tclass,
+                                  FILE__WRITE,
+                                  filename);
+     }
+     PG_CATCH();
+     {
+         freecon(tcontext);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(tcontext);
+
+     checkLargeObjectPages(loid, SnapshotNow, -1, -1,
+                           DB_BLOB__READ | DB_BLOB__EXPORT);
+ }
+
+ void
+ sepgsqlLargeObjectGetSecurity(Relation rel, HeapTuple tuple)
+ {
+     const char *audit_name
+         = sepgsqlTupleName(LargeObjectRelationId, tuple);
+
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                SECCLASS_DB_BLOB,
+                                DB_BLOB__GETATTR,
+                                audit_name);
+ }
+
+ void
+ sepgsqlLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup)
+ {
+     const char *audit_name;
+
+     if (HeapTupleGetSecLabel(newtup) == HeapTupleGetSecLabel(oldtup))
+         return;
+
+     audit_name = sepgsqlTupleName(LargeObjectRelationId, oldtup);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(oldtup),
+                                SECCLASS_DB_BLOB,
+                                DB_BLOB__SETATTR | DB_BLOB__RELABELFROM,
+                                audit_name);
+     /*
+      * check db_blob:{setattr relabelto}
+      */
+     audit_name = sepgsqlTupleName(LargeObjectRelationId, newtup);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(newtup),
+                                SECCLASS_DB_BLOB,
+                                DB_BLOB__RELABELTO,
+                                audit_name);
+ }
+
+ /*******************************************************************************
+  * ExecScan hooks
+  *******************************************************************************/
+ static bool abort_on_violated_tuple = false;
+
+ bool
+ sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot)
+ {
+     HeapTuple    tuple;
+     uint32        perms = (scan->pgaceTuplePerms & SEPGSQL_PERMS_MASK);
+
+     if (perms == 0)
+         return true;
+
+     tuple = ExecMaterializeSlot(slot);
+
+     return sepgsqlCheckTuplePerms(rel, tuple, NULL, perms,
+                                   abort_on_violated_tuple);
+ }
+
+ /* ----------------------------------------------------------
+  * special cases for Foreign Key constraint
+  * ---------------------------------------------------------- */
+ Datum
+ sepgsqlBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid)
+ {
+     Datum save_pgace = BoolGetDatum(abort_on_violated_tuple);
+
+     /*
+      * NOTE: when a tuple is inserted/updated on FK relation, all we should
+      * do is simply filtering violated tuples on PK relation, as normal
+      * row-level access controls doing.
+      * At the result, INSERT/UPDATE with invisible tuple will be failed.
+      */
+     if (is_primary)
+         abort_on_violated_tuple = true;
+
+     return save_pgace;
+ }
+
+ void
+ sepgsqlEndPerformCheckFK(Relation rel, Datum save_pgace)
+ {
+     abort_on_violated_tuple = DatumGetBool(save_pgace);
+ }
+
+ /*******************************************************************************
+  * security_label hooks
+  *******************************************************************************/
+ bool
+ sepgsqlTupleDescHasSecLabel(Relation rel, List *relopts)
+ {
+     /*
+      * Newly created table via SELECT INTO/CREATE TABLE AS
+      */
+     if (rel == NULL)
+         return sepostgresql_row_level;
+
+     if (RelationGetForm(rel)->relkind != RELKIND_RELATION &&
+         RelationGetForm(rel)->relkind != RELKIND_SEQUENCE)
+         return false;
+
+     if (RelationGetRelid(rel) == DatabaseRelationId ||
+         RelationGetRelid(rel) == RelationRelationId ||
+         RelationGetRelid(rel) == AttributeRelationId ||
+         RelationGetRelid(rel) == ProcedureRelationId ||
+         RelationGetRelid(rel) == LargeObjectRelationId)
+         return true;
+
+     return sepostgresql_row_level;
+ }
+
+ char *
+ sepgsqlTranslateSecurityLabelIn(const char *context)
+ {
+     security_context_t i_context;
+     char       *result;
+
+     if (selinux_trans_to_raw_context((security_context_t) context, &i_context) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not translate mls label")));
+     PG_TRY();
+     {
+         result = pstrdup(i_context);
+     }
+     PG_CATCH();
+     {
+         freecon(i_context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(i_context);
+
+     return result;
+ }
+
+ char *
+ sepgsqlTranslateSecurityLabelOut(const char *context)
+ {
+     security_context_t o_context;
+     char       *result;
+
+     if (selinux_raw_to_trans_context((security_context_t) context, &o_context) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not translate mls label")));
+     PG_TRY();
+     {
+         result = pstrdup(o_context);
+     }
+     PG_CATCH();
+     {
+         freecon(o_context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(o_context);
+
+     return result;
+ }
+
+ /*
+  * sepgsqlCheckValidSecurityLabel() checks whether the given
+  * security context is valid on the current working security
+  * policy, or not.
+  * If it's invalid, sepgsqlUnlabeledSecurityLabel() is invoked
+  * at the next to get an alternative security label.
+  */
+ bool
+ sepgsqlCheckValidSecurityLabel(char *context)
+ {
+     if (security_check_context_raw((security_context_t) context) < 0)
+         return false;
+
+     return true;
+ }
+
+ char *
+ sepgsqlUnlabeledSecurityLabel(void)
+ {
+     security_context_t unlabeled;
+     char *result;
+
+     if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not get unlabeled initial context")));
+     PG_TRY();
+     {
+         result = pstrdup(unlabeled);
+     }
+     PG_CATCH();
+     {
+         freecon(unlabeled);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(unlabeled);
+
+     return result;
+ }
+
+ char *
+ sepgsqlSecurityLabelOfLabel(void)
+ {
+     security_context_t table_context, tuple_context;
+     HeapTuple    tuple;
+
+     /*
+      * obtain security context of pg_security
+      */
+     tuple = SearchSysCache(RELOID,
+                            ObjectIdGetDatum(SecurityRelationId), 0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "SELinux: cache lookup failed for relation %u",
+                     SecurityRelationId);
+
+     table_context = pgaceLookupSecurityLabel(HeapTupleGetSecLabel(tuple));
+     if (!table_context || !pgaceCheckValidSecurityLabel(table_context))
+         table_context = pgaceUnlabeledSecurityLabel();
+
+     tuple_context = sepgsqlComputeCreateContext(sepgsqlGetServerContext(),
+                                                 table_context, SECCLASS_DB_TUPLE);
+     pfree(table_context);
+
+     ReleaseSysCache(tuple);
+
+     return tuple_context;
+ }
+
+ /******************************************************************
+  * HeapTuple modification hooks
+  ******************************************************************/
+ static HeapTuple
+ getHeapTupleFromItemPointer(Relation rel, ItemPointer tid)
+ {
+     /*
+      * obtain an old tuple
+      */
+     Buffer        buffer;
+     PageHeader    dp;
+     ItemId        lp;
+     HeapTupleData tuple;
+     HeapTuple    oldtup;
+
+     buffer = ReadBuffer(rel, ItemPointerGetBlockNumber(tid));
+     LockBuffer(buffer, BUFFER_LOCK_SHARE);
+
+     dp = (PageHeader) BufferGetPage(buffer);
+     lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+
+     Assert(ItemIdIsNormal(lp));
+
+     tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
+     tuple.t_len = ItemIdGetLength(lp);
+     tuple.t_self = *tid;
+     tuple.t_tableOid = RelationGetRelid(rel);
+     oldtup = heap_copytuple(&tuple);
+
+     LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+     ReleaseBuffer(buffer);
+
+     return oldtup;
+ }
+
+ static bool
+ isTrustedRelation(Relation rel, bool is_internal)
+ {
+     if (!is_internal)
+         return false;
+
+     if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
+         return true;
+
+     switch (RelationGetRelid(rel))
+     {
+         case LargeObjectRelationId:
+         case SecurityRelationId:
+             return true;
+     }
+     return false;
+ }
+
+ bool
+ sepgsqlHeapTupleInsert(Relation rel, HeapTuple tuple,
+                        bool is_internal, bool with_returning)
+ {
+     uint32        perms;
+
+     /*
+      * default context for no explicit labeled tuple
+      */
+     if (!OidIsValid(HeapTupleGetSecLabel(tuple)))
+     {
+         /*
+          * If user gives no valid security context,
+          * it assigns a default one on the new tuple.
+          */
+         if (HeapTupleHasSecLabel(tuple))
+             sepgsqlSetDefaultContext(rel, tuple);
+     }
+     else if (!is_internal && RelationGetRelid(rel) == LargeObjectRelationId)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: unable to insert "
+                         "pg_largeobject.security_label")));
+
+     if (isTrustedRelation(rel, is_internal))
+         return true;
+
+     perms = SEPGSQL_PERMS_INSERT;
+     if (with_returning)
+         perms |= SEPGSQL_PERMS_SELECT;
+
+     return sepgsqlCheckTuplePerms(rel, tuple, NULL, perms, is_internal);
+ }
+
+ bool
+ sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
+                        bool is_internal, bool with_returning)
+ {
+     Oid            relid = RelationGetRelid(rel);
+     HeapTuple    oldtup;
+     uint32        perms;
+     bool        rc = true;
+     bool        relabel = false;
+
+     oldtup = getHeapTupleFromItemPointer(rel, otid);
+
+     if (!OidIsValid(HeapTupleGetSecLabel(newtup)))
+     {
+         /*
+          * If user does not specify new security context
+          * explicitly, it preserves a security context of
+          * older tuple.
+          */
+         Oid sid = HeapTupleGetSecLabel(oldtup);
+
+         if (HeapTupleHasSecLabel(newtup))
+             HeapTupleSetSecLabel(newtup, sid);
+     }
+     else if (!is_internal && RelationGetRelid(rel) == LargeObjectRelationId)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: unable to update "
+                         "pg_largeobject.security_label")));
+
+     if (isTrustedRelation(rel, is_internal))
+         return true;
+
+     if (HeapTupleGetSecLabel(newtup) != HeapTupleGetSecLabel(oldtup) ||
+         sepgsqlTupleObjectClass(relid, newtup) != sepgsqlTupleObjectClass(relid, oldtup))
+         relabel = true;
+
+     perms = SEPGSQL_PERMS_UPDATE;
+     if (relabel)
+         perms |= SEPGSQL_PERMS_RELABELFROM;
+     rc = sepgsqlCheckTuplePerms(rel, oldtup, newtup, perms, is_internal);
+     if (!rc)
+         goto out;
+
+     if (relabel)
+     {
+         perms = SEPGSQL_PERMS_RELABELTO;
+         if (with_returning)
+             perms |= SEPGSQL_PERMS_SELECT;
+         rc = sepgsqlCheckTuplePerms(rel, newtup, NULL, perms, is_internal);
+     }
+   out:
+     heap_freetuple(oldtup);
+     return rc;
+ }
+
+ bool
+ sepgsqlHeapTupleDelete(Relation rel, ItemPointer otid,
+                        bool is_internal, bool with_returning)
+ {
+     HeapTuple    oldtup;
+     uint32        perms = SEPGSQL_PERMS_DELETE;
+     bool        rc;
+
+     if (isTrustedRelation(rel, is_internal))
+         return true;
+
+     oldtup = getHeapTupleFromItemPointer(rel, otid);
+     rc = sepgsqlCheckTuplePerms(rel, oldtup, NULL, perms, is_internal);
+     heap_freetuple(oldtup);
+
+     return rc;
+ }
diff -Nrpc base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/security/sepgsql/permissions.c
*** base/src/backend/security/sepgsql/permissions.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/sepgsql/permissions.c    Thu Jan 22 14:26:56 2009
***************
*** 0 ****
--- 1,785 ----
+ /*
+  * src/backend/security/sepgsql/permissions.c
+  *     applies SE-PostgreSQL permission checks
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+
+ #include "access/heapam.h"
+ #include "access/genam.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_aggregate.h"
+ #include "catalog/pg_am.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_attribute.h"
+ #include "catalog/pg_authid.h"
+ #include "catalog/pg_cast.h"
+ #include "catalog/pg_class.h"
+ #include "catalog/pg_conversion.h"
+ #include "catalog/pg_database.h"
+ #include "catalog/pg_language.h"
+ #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_proc.h"
+ #include "catalog/pg_security.h"
+ #include "catalog/pg_trigger.h"
+ #include "catalog/pg_ts_parser.h"
+ #include "catalog/pg_ts_template.h"
+ #include "catalog/pg_type.h"
+ #include "miscadmin.h"
+ #include "security/pgace.h"
+ #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
+ #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+
+ /*
+  * It can be configured via a GUC variable to toggle
+  * row-level access controls.
+  */
+ bool sepostgresql_row_level;
+
+ /*
+  * sepgsqlTupleName
+  *   returns an identifier string to generate audit record for
+  *   the given tuple. Please note that its results can indicate
+  *   an address within the given tuple, so we should not refer
+  *   the returned pointer after HeapTuple is released.
+  */
+ const char *
+ sepgsqlTupleName(Oid relid, HeapTuple tuple)
+ {
+     static char buffer[NAMEDATALEN * 2 + 10];
+
+     switch (relid)
+     {
+     case DatabaseRelationId:
+         return NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname);
+
+     case RelationRelationId:
+         return NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
+
+     case AttributeRelationId:
+         if (!IsBootstrapProcessingMode())
+         {
+             Form_pg_attribute attForm
+                 = (Form_pg_attribute) GETSTRUCT(tuple);
+             char *relname
+                 = get_rel_name(attForm->attrelid);
+
+             if (relname)
+             {
+                 snprintf(buffer, sizeof(buffer), "%s.%s",
+                          relname, NameStr(attForm->attname));
+                 pfree(relname);
+                 return buffer;
+             }
+         }
+         return NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname);
+
+     case ProcedureRelationId:
+         return NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname);
+
+     case LargeObjectRelationId:
+         snprintf(buffer, sizeof(buffer), "loid:%u",
+                  ((Form_pg_largeobject) GETSTRUCT(tuple))->loid);
+         return buffer;
+     }
+     return NULL;    /* No tuple name for audit record */
+ }
+
+ /*
+  * sepgsqlFileObjectClass
+  *
+  * It returns proper object class of filesystem object already opened.
+  * It is necessary to check privileges voluntarily.
+  */
+ security_class_t
+ sepgsqlFileObjectClass(int fdesc, const char *filename)
+ {
+     struct stat stbuf;
+
+     if (fstat(fdesc, &stbuf) != 0)
+         ereport(ERROR,
+                 (errcode_for_file_access(),
+                  errmsg("could not stat file \"%s\": %m", filename)));
+
+     if (S_ISDIR(stbuf.st_mode))
+         return SECCLASS_DIR;
+     else if (S_ISCHR(stbuf.st_mode))
+         return SECCLASS_CHR_FILE;
+     else if (S_ISBLK(stbuf.st_mode))
+         return SECCLASS_BLK_FILE;
+     else if (S_ISFIFO(stbuf.st_mode))
+         return SECCLASS_FIFO_FILE;
+     else if (S_ISLNK(stbuf.st_mode))
+         return SECCLASS_LNK_FILE;
+     else if (S_ISSOCK(stbuf.st_mode))
+         return SECCLASS_SOCK_FILE;
+
+     return SECCLASS_FILE;
+ }
+
+ /*
+  * sepgsqlTupleObjectClass
+  *
+  * It returns proper object class of given tuple
+  */
+ security_class_t
+ sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple)
+ {
+     Form_pg_class clsForm;
+     Form_pg_attribute attForm;
+
+     switch (relid)
+     {
+         case DatabaseRelationId:
+             return SECCLASS_DB_DATABASE;
+
+         case RelationRelationId:
+             clsForm = (Form_pg_class) GETSTRUCT(tuple);
+             if (clsForm->relkind == RELKIND_RELATION)
+                 return SECCLASS_DB_TABLE;
+             break;
+
+         case AttributeRelationId:
+             attForm = (Form_pg_attribute) GETSTRUCT(tuple);
+             if (attForm->attkind == RELKIND_RELATION)
+                 return SECCLASS_DB_COLUMN;
+             break;
+
+         case ProcedureRelationId:
+             return SECCLASS_DB_PROCEDURE;
+
+         case LargeObjectRelationId:
+             return SECCLASS_DB_BLOB;
+     }
+
+     return SECCLASS_DB_TUPLE;
+ }
+
+ /*
+  * sepgsqlCheckTuplePerms
+  *
+  * This function evaluates given permission set (SEPGSQL_PERMS_*) onto the
+  * given tuple, with translating them into proper SELinux permission.
+  *
+  * Accesses to some of system catalog has special meanings. DELETE a tuple
+  * within pg_class also means DROP TABLE for instance. In this case,
+  * SE-PostgreSQL translate given SEPGSQL_PERMS_DELETE into DB_TABLE__DROP
+  * to keep consistency of user operation. To delete a tuple within pg_class
+  * always means dropping a table independent from what SQL statement is
+  * used.
+  *
+  * Thus, checks for some of system catalog need to modify given permission
+  * set at checkTuplePermsXXXX() functions.
+  */
+ static access_vector_t
+ sepgsqlPermsToCommonAv(uint32 perms)
+ {
+     access_vector_t result = 0;
+
+     result |= (perms & SEPGSQL_PERMS_USE         ? COMMON_DATABASE__GETATTR : 0);
+     result |= (perms & SEPGSQL_PERMS_SELECT      ? COMMON_DATABASE__GETATTR : 0);
+     result |= (perms & SEPGSQL_PERMS_UPDATE      ? COMMON_DATABASE__SETATTR : 0);
+     result |= (perms & SEPGSQL_PERMS_INSERT      ? COMMON_DATABASE__CREATE : 0);
+     result |= (perms & SEPGSQL_PERMS_DELETE      ? COMMON_DATABASE__DROP : 0);
+     result |= (perms & SEPGSQL_PERMS_RELABELFROM ? COMMON_DATABASE__RELABELFROM : 0);
+     result |= (perms & SEPGSQL_PERMS_RELABELTO   ? COMMON_DATABASE__RELABELTO : 0);
+
+     return result;
+ }
+
+ static access_vector_t
+ sepgsqlPermsToDatabaseAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
+ {
+     return sepgsqlPermsToCommonAv(perms);
+ }
+
+ static access_vector_t
+ sepgsqlPermsToTableAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
+ {
+     return sepgsqlPermsToCommonAv(perms);
+ }
+
+ static access_vector_t
+ sepgsqlPermsToProcedureAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
+ {
+     access_vector_t result = sepgsqlPermsToCommonAv(perms);
+     Form_pg_proc proForm;
+     HeapTuple protup;
+     Datum probin;
+     bool isnull;
+
+     /*
+      * Check permission for loadable module installation
+      */
+     protup = HeapTupleIsValid(newtup) ? newtup : tuple;
+     proForm = (Form_pg_proc) GETSTRUCT(protup);
+
+     if (proForm->prolang == ClanguageId)
+     {
+         bool need_check = false;
+
+         probin = SysCacheGetAttr(PROCOID, protup,
+                                  Anum_pg_proc_probin,
+                                  &isnull);
+         if (!isnull)
+         {
+             if (result & DB_PROCEDURE__CREATE)
+                 need_check = true;
+             else if (HeapTupleIsValid(newtup))
+             {
+                 Form_pg_proc oldForm = (Form_pg_proc) GETSTRUCT(tuple);
+
+                 if (oldForm->prolang != proForm->prolang)
+                     need_check = true;
+                 else
+                 {
+                     Datum oldbin = SysCacheGetAttr(PROCOID, tuple,
+                                                    Anum_pg_proc_probin,
+                                                    &isnull);
+                     if (isnull)
+                         need_check = true;
+                     else
+                     {
+                         Datum comp = DirectFunctionCall2(byteane, oldbin, probin);
+                         need_check = DatumGetBool(comp);
+                     }
+                 }
+             }
+
+             if (need_check)
+             {
+                 char *filename = TextDatumGetCString(probin);
+
+                 sepgsqlCheckModuleInstallPerms(filename);
+             }
+         }
+     }
+
+     return result;
+ }
+
+ static access_vector_t
+ sepgsqlPermsToColumnAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
+ {
+     access_vector_t result = sepgsqlPermsToCommonAv(perms);
+
+     if (HeapTupleIsValid(newtup))
+     {
+         Form_pg_attribute oldatt = (Form_pg_attribute) GETSTRUCT(tuple);
+         Form_pg_attribute newatt = (Form_pg_attribute) GETSTRUCT(newtup);
+
+         if (!oldatt->attisdropped && newatt->attisdropped)
+             result |= DB_COLUMN__DROP;
+         if (oldatt->attisdropped && !newatt->attisdropped)
+             result |= DB_COLUMN__CREATE;
+     }
+     return result;
+ }
+
+ static access_vector_t
+ sepgsqlPermsToTupleAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
+ {
+     access_vector_t result = 0;
+
+     result |= (perms & SEPGSQL_PERMS_USE         ? DB_TUPLE__USE : 0);
+     result |= (perms & SEPGSQL_PERMS_SELECT      ? DB_TUPLE__SELECT : 0);
+     result |= (perms & SEPGSQL_PERMS_UPDATE      ? DB_TUPLE__UPDATE : 0);
+     result |= (perms & SEPGSQL_PERMS_INSERT      ? DB_TUPLE__INSERT : 0);
+     result |= (perms & SEPGSQL_PERMS_DELETE      ? DB_TUPLE__DELETE : 0);
+     result |= (perms & SEPGSQL_PERMS_RELABELFROM ? DB_TUPLE__RELABELFROM : 0);
+     result |= (perms & SEPGSQL_PERMS_RELABELTO   ? DB_TUPLE__RELABELTO : 0);
+
+     return result;
+ }
+
+ static access_vector_t
+ sepgsqlPermsToBlobAv(uint32 perms, HeapTuple tuple, HeapTuple newtup)
+ {
+     access_vector_t result = sepgsqlPermsToCommonAv(perms);
+
+     /*
+      * NOTE: INSERT tuples into pg_largeobject has a possibility to create
+      * a new largeobject, if the given loid is not exist on the current
+      * pg_largeobject. Ditto for DELETE statement, it also has a possibility
+      * to drop a largeobject, if it removes all tuples within a large object.
+      *
+      * UPDATE pg_largeobject.loid has a possibility to create and drop
+      * a largeobject in same time, so we need to check it when loid is
+      * changed.
+      *
+      * db_blob:{create} and db_blob:{drop} should be evaluated for
+      * creation/deletion of largeobject, but we have to check pg_largeobject
+      * with SnapshotSelf whether there is one or more tuple having same loid,
+      * or not, on each tuple insertion or deletion.
+      *
+      * So, we assume any INSERT means db_blob:{create}, any DELETE means
+      * db_blob:{drop}.
+      */
+     result |= (perms & SEPGSQL_PERMS_INSERT    ? DB_BLOB__WRITE : 0);
+     if (perms & SEPGSQL_PERMS_UPDATE)
+     {
+         result |= DB_BLOB__WRITE;
+
+         if (((Form_pg_largeobject) GETSTRUCT(tuple))->loid !=
+             ((Form_pg_largeobject) GETSTRUCT(newtup))->loid)
+             result |= (DB_BLOB__CREATE | DB_BLOB__DROP);
+     }
+     result |= (perms & SEPGSQL_PERMS_DELETE    ? DB_BLOB__WRITE : 0);
+     result |= (perms & SEPGSQL_PERMS_READ    ? DB_BLOB__READ  : 0);
+
+     return result;
+ }
+
+ /*
+  * sepgsqlCheckProcedureInstall
+  *   checks permission: db_procedure:{install}, when client tries to modify
+  *   a system catalog which contains procedure id to invoke it later.
+  *   Because these functions are invoked internally, to search a table with
+  *   a special index algorithm for example, the security policy has to prevent
+  *   malicious user-defined functions to be installed.
+  */
+ static void
+ checkProcedureInstall(Oid proc_oid)
+ {
+     if (!OidIsValid(proc_oid))
+         return;
+
+     if (IsBootstrapProcessingMode())
+     {
+         /*
+          * We assume all procedures have same security context
+          * in bootstrap processing mode, because no one can
+          * relabel it.
+          */
+         Oid proc_sid
+             = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
+                                      SECCLASS_DB_PROCEDURE);
+         sepgsqlClientHasPermission(proc_sid,
+                                    SECCLASS_DB_PROCEDURE,
+                                    DB_PROCEDURE__INSTALL,
+                                    NULL);
+     }
+     else
+     {
+         HeapTuple protup;
+         const char *audit_name;
+
+         protup = SearchSysCache(PROCOID,
+                                 ObjectIdGetDatum(proc_oid),
+                                 0, 0, 0);
+         if (!HeapTupleIsValid(protup))
+             return;
+
+         audit_name = sepgsqlTupleName(ProcedureRelationId, protup);
+         sepgsqlClientHasPermission(HeapTupleGetSecLabel(protup),
+                                    SECCLASS_DB_PROCEDURE,
+                                    DB_PROCEDURE__INSTALL,
+                                    audit_name);
+         ReleaseSysCache(protup);
+     }
+ }
+
+ #define CHECK_PROC_INSTALL_HANDLER(catalog,member,tuple,newtup)            \
+     do {                                                                \
+         if (!HeapTupleIsValid(newtup))                                    \
+             checkProcedureInstall(((CppConcat(Form_,catalog)) GETSTRUCT(tuple))->member); \
+         else if (((CppConcat(Form_,catalog)) GETSTRUCT(tuple))->member    \
+                  != ((CppConcat(Form_,catalog)) GETSTRUCT(newtup))->member) \
+             checkProcedureInstall(((CppConcat(Form_,catalog)) GETSTRUCT(newtup))->member); \
+     } while(0)
+
+ static void
+ sepgsqlCheckProcedureInstall(Relation rel, HeapTuple tuple, HeapTuple newtup)
+ {
+     /*
+      * Some of system catalog can be configured to invoke functions
+      * implicitly. It checks permission to prevent implicit invocation
+      * of malicious functions.
+      */
+     switch (RelationGetRelid(rel))
+     {
+     case AggregateRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfnoid, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggtransfn, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfinalfn, tuple, newtup);
+         break;
+
+     case AccessMethodRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_am, aminsert, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, ambeginscan, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amgettuple, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amgetbitmap, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amrescan, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amendscan, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, ammarkpos, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amrestrpos, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, ambuild, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, ambulkdelete, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amvacuumcleanup, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amcostestimate, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_am, amoptions, tuple, newtup);
+         break;
+
+     case AccessMethodProcedureRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_amproc, amproc, tuple, newtup);
+         break;
+
+     case CastRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_cast, castfunc, tuple, newtup);
+         break;
+
+     case ConversionRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_conversion, conproc, tuple, newtup);
+         break;
+
+     case LanguageRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_language, lanplcallfoid, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_language, lanvalidator, tuple, newtup);
+         break;
+
+     case OperatorRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_operator, oprcode, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_operator, oprrest, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_operator, oprjoin, tuple, newtup);
+         break;
+
+     case TriggerRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_trigger, tgfoid, tuple, newtup);
+         break;
+
+     case TSParserRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsstart, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prstoken, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsend, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsheadline, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prslextype, tuple, newtup);
+         break;
+
+     case TSTemplateRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmplinit, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmpllexize, tuple, newtup);
+         break;
+
+     case TypeRelationId:
+         CHECK_PROC_INSTALL_HANDLER(pg_type, typinput, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_type, typoutput, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_type, typreceive, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_type, typsend, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_type, typmodin, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_type, typmodout, tuple, newtup);
+         CHECK_PROC_INSTALL_HANDLER(pg_type, typanalyze, tuple, newtup);
+         break;
+     }
+ }
+
+ bool
+ sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple newtup,
+                        uint32 perms, bool abort)
+ {
+     security_class_t tclass;
+     access_vector_t av = 0;
+     bool rc = true;
+
+     Assert(HeapTupleIsValid(tuple));
+
+     if ((perms & (SEPGSQL_PERMS_INSERT | SEPGSQL_PERMS_UPDATE)) != 0)
+         sepgsqlCheckProcedureInstall(rel, tuple, newtup);
+
+     tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
+
+     switch (tclass)
+     {
+         case SECCLASS_DB_DATABASE:
+             av = sepgsqlPermsToDatabaseAv(perms, tuple, newtup);
+             break;
+
+         case SECCLASS_DB_TABLE:
+             av = sepgsqlPermsToTableAv(perms, tuple, newtup);
+             break;
+
+         case SECCLASS_DB_PROCEDURE:
+             av = sepgsqlPermsToProcedureAv(perms, tuple, newtup);
+             break;
+
+         case SECCLASS_DB_COLUMN:
+             av = sepgsqlPermsToColumnAv(perms, tuple, newtup);
+             break;
+
+         case SECCLASS_DB_BLOB:
+             av = sepgsqlPermsToBlobAv(perms, tuple, newtup);
+             break;
+
+         default: /* SECCLASS_DB_TUPLE */
+             if (sepostgresql_row_level)
+                 av = sepgsqlPermsToTupleAv(perms, tuple, newtup);
+             break;
+     }
+
+     if (av)
+     {
+         const char *audit_name
+             = sepgsqlTupleName(RelationGetRelid(rel), tuple);
+
+         if (abort)
+         {
+             sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                        tclass, av, audit_name);
+         }
+         else
+         {
+             rc = sepgsqlClientHasPermissionNoAbort(HeapTupleGetSecLabel(tuple),
+                                                    tclass, av, audit_name);
+         }
+     }
+
+     return rc;
+ }
+
+ /*
+  * sepgsqlCheckModuleInstallPerms
+  *
+  * It checks client's privilege to install a new shared loadable file.
+  */
+ void
+ sepgsqlCheckModuleInstallPerms(const char *filename)
+ {
+     security_context_t file_context;
+     Form_pg_database dbform;
+     HeapTuple dbtup;
+     char *fullpath;
+
+     /* (client) <-- db_database:module_install --> (database) */
+     dbtup = SearchSysCache(DATABASEOID,
+                            ObjectIdGetDatum(MyDatabaseId),
+                            0, 0, 0);
+     if (!HeapTupleIsValid(dbtup))
+         elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId);
+
+     dbform = (Form_pg_database) GETSTRUCT(dbtup);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(dbtup),
+                                SECCLASS_DB_DATABASE,
+                                DB_DATABASE__INSTALL_MODULE,
+                                NameStr(dbform->datname));
+     ReleaseSysCache(dbtup);
+
+     /* (client) <-- db_databse:module_install --> (*.so file) */
+     fullpath = expand_dynamic_library_name(filename);
+     if (getfilecon_raw(fullpath, &file_context) < 0)
+         ereport(ERROR,
+                 (errcode_for_file_access(),
+                  errmsg("could not access file \"%s\": %m", fullpath)));
+     PG_TRY();
+     {
+         sepgsqlComputePermission(sepgsqlGetClientContext(),
+                                  file_context,
+                                  SECCLASS_DB_DATABASE,
+                                  DB_DATABASE__INSTALL_MODULE,
+                                  fullpath);
+     }
+     PG_CATCH();
+     {
+         freecon(file_context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(file_context);
+ }
+
+ /*
+  * sepgsqlSetDefaultContext
+  *
+  * This function attach a proper security context for a newly inserted tuple,
+  * refering the security policy.
+  * In the default, any tuple inherits the security context of its table.
+  * However, we have several exception for some of system catalog. It come from
+  * TYPE_TRANSITION rules in the security policy.
+  */
+ static Oid
+ sepgsqlDefaultDatabaseContext(Relation rel, HeapTuple tuple)
+ {
+     security_context_t newcon;
+
+     newcon = sepgsqlComputeCreateContext(sepgsqlGetClientContext(),
+                                          sepgsqlGetClientContext(),
+                                          SECCLASS_DB_DATABASE);
+     return pgaceSecurityLabelToSid(newcon);
+ }
+
+ static Oid
+ sepgsqlDefaultTableContext(Relation rel, HeapTuple tuple)
+ {
+     return sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
+                                   SECCLASS_DB_TABLE);
+ }
+
+ static Oid
+ sepgsqlDefaultProcedureContext(Relation rel, HeapTuple tuple)
+ {
+     return sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
+                                   SECCLASS_DB_PROCEDURE);
+ }
+
+ static Oid
+ sepgsqlDefaultColumnContext(Relation rel, HeapTuple tuple)
+ {
+     Form_pg_attribute attForm;
+     Oid tblsid;
+
+     attForm = (Form_pg_attribute) GETSTRUCT(tuple);
+
+     if (IsBootstrapProcessingMode() &&
+         (attForm->attrelid == TypeRelationId ||
+          attForm->attrelid == ProcedureRelationId ||
+          attForm->attrelid == AttributeRelationId ||
+          attForm->attrelid == RelationRelationId))
+     {
+         /*
+          * We cannot access relation caches on very early phase
+          * in bootstrap, so it assumes tables has default security
+          * context and unlabeled by initdb.
+          */
+         tblsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
+                                         SECCLASS_DB_TABLE);
+     }
+     else
+     {
+         HeapTuple reltup
+             = SearchSysCache(RELOID,
+                              ObjectIdGetDatum(attForm->attrelid),
+                              0, 0, 0);
+         if (!HeapTupleIsValid(reltup))
+             elog(ERROR, "SELinux: cache lookup failed for relation: %u",
+                  attForm->attrelid);
+
+         tblsid = HeapTupleGetSecLabel(reltup);
+
+         ReleaseSysCache(reltup);
+     }
+
+     return sepgsqlClientCreateSid(tblsid, SECCLASS_DB_COLUMN);
+ }
+
+ static Oid
+ sepgsqlDefaultTupleContext(Relation rel, HeapTuple tuple)
+ {
+     Oid tblsid;
+
+     if (IsBootstrapProcessingMode() &&
+         (RelationGetRelid(rel) == TypeRelationId ||
+          RelationGetRelid(rel) == ProcedureRelationId ||
+          RelationGetRelid(rel) == AttributeRelationId ||
+          RelationGetRelid(rel) == RelationRelationId))
+     {
+         /*
+          * We cannot access relation caches on very early phase
+          * in bootstrap, so it assumes tables has default security
+          * context and unlabeled by initdb.
+          */
+         tblsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
+                                         SECCLASS_DB_TABLE);
+     }
+     else
+     {
+         HeapTuple reltup
+             = SearchSysCache(RELOID,
+                              ObjectIdGetDatum(RelationGetRelid(rel)),
+                              0, 0, 0);
+         if (!HeapTupleIsValid(reltup))
+             elog(ERROR, "SELinux: cache lookup failed for relation: %u",
+                  RelationGetRelid(rel));
+
+         tblsid = HeapTupleGetSecLabel(reltup);
+
+         ReleaseSysCache(reltup);
+     }
+
+     return sepgsqlClientCreateSid(tblsid, SECCLASS_DB_TUPLE);
+ }
+
+ static Oid
+ sepgsqlDefaultBlobContext(Relation rel, HeapTuple tuple)
+ {
+     /*
+      * NOTE:
+      * A new tuple to be inserted into pg_largeobject inherits
+      * a security context of prior tuples of same large object.
+      * The "SnapshotNow" is available for this purpose because
+      * lo_create() invokes CommandCounterIncrement() just after
+      * creation of a new large object.
+      *
+      * If we can find no prior tuples, it means this action to
+      * insert the first page, or client invokes INSERT INTO ...
+      * with multiple tuples with same loid. However, these
+      * tuples are labeled by same TYPE_TRANSITION rules in both
+      * cases. So, there are no differences.
+      */
+     Form_pg_largeobject loForm
+         = (Form_pg_largeobject) GETSTRUCT(tuple);
+     ScanKeyData        skey;
+     SysScanDesc        scan;
+     HeapTuple        lotup;
+     Oid                newsid = InvalidOid;
+
+     ScanKeyInit(&skey,
+                 Anum_pg_largeobject_loid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(loForm->loid));
+     scan = systable_beginscan(rel,
+                               LargeObjectLOidPNIndexId, true,
+                               SnapshotNow, 1, &skey);
+     while ((lotup = systable_getnext(scan)) != NULL)
+     {
+         newsid = HeapTupleGetSecLabel(lotup);
+         if (OidIsValid(newsid))
+             break;
+     }
+     systable_endscan(scan);
+
+     if (!OidIsValid(newsid))
+     {
+         newsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(),
+                                         SECCLASS_DB_BLOB);
+     }
+
+     return newsid;
+ }
+
+ void
+ sepgsqlSetDefaultContext(Relation rel, HeapTuple tuple)
+ {
+     security_class_t tclass;
+     Oid newsid;
+
+     Assert(HeapTupleHasSecLabel(tuple));
+     tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple);
+
+     switch (tclass)
+     {
+         case SECCLASS_DB_DATABASE:
+             newsid = sepgsqlDefaultDatabaseContext(rel, tuple);
+             break;
+         case SECCLASS_DB_TABLE:
+             newsid = sepgsqlDefaultTableContext(rel, tuple);
+             break;
+         case SECCLASS_DB_PROCEDURE:
+             newsid = sepgsqlDefaultProcedureContext(rel, tuple);
+             break;
+         case SECCLASS_DB_COLUMN:
+             newsid = sepgsqlDefaultColumnContext(rel, tuple);
+             break;
+         case SECCLASS_DB_BLOB:
+             newsid = sepgsqlDefaultBlobContext(rel, tuple);
+             break;
+         default: /* SECCLASS_DB_TUPLE */
+             newsid = sepgsqlDefaultTupleContext(rel, tuple);
+             break;
+     }
+
+     HeapTupleSetSecLabel(tuple, newsid);
+ }
diff -Nrpc base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/security/sepgsql/proxy.c
*** base/src/backend/security/sepgsql/proxy.c    Thu Jan  1 09:00:00 1970
--- sepgsql/src/backend/security/sepgsql/proxy.c    Fri Jan 23 13:05:55 2009
***************
*** 0 ****
--- 1,1097 ----
+ /*
+  * src/backend/security/sepgsql/proxy.c
+  *    Proxying the given Query trees via SE-PostgreSQL
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+
+ #include "access/genam.h"
+ #include "access/heapam.h"
+ #include "access/sysattr.h"
+ #include "catalog/heap.h"
+ #include "catalog/indexing.h"
+ #include "catalog/namespace.h"
+ #include "catalog/pg_attribute.h"
+ #include "catalog/pg_class.h"
+ #include "catalog/pg_constraint.h"
+ #include "catalog/pg_database.h"
+ #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_proc.h"
+ #include "catalog/pg_security.h"
+ #include "catalog/pg_trigger.h"
+ #include "catalog/pg_type.h"
+ #include "executor/executor.h"
+ #include "nodes/nodeFuncs.h"
+ #include "nodes/security.h"
+ #include "optimizer/clauses.h"
+ #include "optimizer/plancat.h"
+ #include "optimizer/prep.h"
+ #include "optimizer/tlist.h"
+ #include "parser/parsetree.h"
+ #include "security/pgace.h"
+ #include "storage/lock.h"
+ #include "utils/array.h"
+ #include "utils/fmgroids.h"
+ #include "utils/fmgrtab.h"
+ #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+
+ /*
+  * sepgsqlWalkerContext
+  *
+  * This structure holds a context during analyzing a given query.
+  * selist is a list of SEvalItemXXX objects to enumerate appared
+  * tables and columns. These are evaluated later, just before
+  * executing query.
+  * is_internal_use shows the current state whether the current
+  * Node is chained with target list, or conditional clause.
+  */
+ typedef struct sepgsqlWalkerContext
+ {
+     struct sepgsqlWalkerContext *parent;
+     Query  *query;    /* Query structure of current layer */
+     List   *selist;    /* list of SEvalItemXXX */
+     bool    is_internal_use;
+ } sepgsqlWalkerContext;
+
+ #define seitem_index_to_attno(index)            \
+     ((index) + FirstLowInvalidHeapAttributeNumber + 1)
+ #define seitem_attno_to_index(attno)            \
+     ((attno) - FirstLowInvalidHeapAttributeNumber - 1)
+
+
+ /*
+  * addEvalRelation
+  * addEvalRelationRTE
+  *
+  * These functions add a given relation into selist, if it is not
+  * contained yet. In addition, addEvalRelationRTE also marks required
+  * permissions on rte->pgaceTuplePerms. It is delivered to Scan object
+  * and we can use it on ExecScan hook to apply tuple-level access
+  * controls.
+  */
+ static List *
+ addEvalRelation(List *selist, Oid relid, bool inh, uint32 perms)
+ {
+     SelinuxEvalItem *seitem;
+     Form_pg_class relForm;
+     HeapTuple tuple;
+     ListCell *l;
+
+     foreach (l, selist)
+     {
+         seitem = (SelinuxEvalItem *) lfirst(l);
+         Assert(IsA(seitem, SelinuxEvalItem));
+
+         if (seitem->relid == relid && seitem->inh == inh)
+         {
+             seitem->relperms |= perms;
+             return selist;
+         }
+     }
+
+     /* not found, so create a new one */
+     tuple = SearchSysCache(RELOID,
+                            ObjectIdGetDatum(relid),
+                            0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "cache lookup failed for relation %u", relid);
+     relForm = (Form_pg_class) GETSTRUCT(tuple);
+
+     seitem = makeNode(SelinuxEvalItem);
+     seitem->relid = relid;
+     seitem->inh = inh;
+     seitem->relperms = perms;
+     seitem->nattrs = seitem_attno_to_index(relForm->relnatts) + 1;
+     seitem->attperms = palloc0(seitem->nattrs * sizeof(uint32));
+
+     ReleaseSysCache(tuple);
+
+     return lappend(selist, seitem);
+ }
+
+ static List *
+ addEvalRelationRTE(List *selist, RangeTblEntry *rte, uint32 perms)
+ {
+     rte->pgaceTuplePerms |= (perms & DB_TABLE__USE ? SEPGSQL_PERMS_USE : 0);
+     rte->pgaceTuplePerms |=    (perms & DB_TABLE__SELECT ? SEPGSQL_PERMS_SELECT : 0);
+
+     return addEvalRelation(selist, rte->relid, rte->inh, perms);
+ }
+
+ /*
+  * addEvalAttribute
+  * addEvalAttributeRTE
+  *
+  * These functions add a given attribute into selist, if it is not
+  * contained yet. In addition, addEvalAttributeRTE also marks required
+  * permissions on rte->pgaceTuplePerms. It is delivered to Scan object
+  * and we can use it on ExecScan hook to apply tuple-level access
+  * controls.
+  */
+ static List *
+ addEvalAttribute(List *selist, Oid relid, bool inh, AttrNumber attno, uint32 perms)
+ {
+     SelinuxEvalItem *seitem;
+     Form_pg_class relForm;
+     HeapTuple tuple;
+     ListCell *l;
+     int index = seitem_attno_to_index(attno);
+
+     foreach (l, selist)
+     {
+         seitem = (SelinuxEvalItem *) lfirst(l);
+         Assert(IsA(seitem, SelinuxEvalItem));
+
+         if (seitem->relid == relid && seitem->inh == inh)
+         {
+             if (index >= seitem->nattrs)
+             {
+                 uint32 *attperms, nattrs;
+
+                 /*
+                  * NOTE: the following step has a possibility that
+                  * index number overs seitem->nattrs
+                  *
+                  * 1. PREPARE p AS SELECT t FROM t;
+                  * 2. ALTER TABLE t ADD COLUMN x int;
+                  * 3. EXECUTE p;
+                  *
+                  * Because whole-row-reference is extracted to
+                  * references to all the user columns, so table
+                  * may have different number of columns between
+                  * state.1 and state.3.
+                  * In this case, we need to rebuild seitem->attperms
+                  */
+
+                 tuple = SearchSysCache(RELOID,
+                                        ObjectIdGetDatum(relid),
+                                        0, 0, 0);
+                 if (!HeapTupleIsValid(tuple))
+                     elog(ERROR, "cache lookup failed for relation %u", relid);
+                 relForm = (Form_pg_class) GETSTRUCT(tuple);
+
+                 nattrs = seitem_attno_to_index(relForm->relnatts) + 1;
+                 attperms = palloc0(nattrs * sizeof(uint32));
+                 memcpy(attperms, seitem->attperms,
+                        seitem->nattrs * sizeof(uint32));
+                 seitem->nattrs = nattrs;
+                 seitem->attperms = attperms;
+
+                 ReleaseSysCache(tuple);
+             }
+
+             if (index < 0 || index >= seitem->nattrs)
+                 elog(ERROR, "SELinux: invalid attribute number: %d at relation: %u",
+                      attno, relid);
+
+             seitem->attperms[index] |= perms;
+
+             return selist;
+         }
+     }
+
+     /* not found, so create a new one */
+     tuple = SearchSysCache(RELOID,
+                            ObjectIdGetDatum(relid),
+                            0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "cache lookup failed for relation %u", relid);
+     relForm = (Form_pg_class) GETSTRUCT(tuple);
+
+     seitem = makeNode(SelinuxEvalItem);
+     seitem->relid = relid;
+     seitem->inh = inh;
+     seitem->relperms = 0;
+     seitem->nattrs = seitem_attno_to_index(relForm->relnatts) + 1;
+     seitem->attperms = palloc0(seitem->nattrs * sizeof(uint32));
+     if (index < 0 || index >= seitem->nattrs)
+         elog(ERROR, "SELinux: invalid attribute number: %d at relation: %u",
+              attno, relid);
+     seitem->attperms[index] |= perms;
+
+     ReleaseSysCache(tuple);
+
+     return lappend(selist, seitem);
+ }
+
+ static List *
+ addEvalAttributeRTE(List *selist, RangeTblEntry *rte, AttrNumber attno, uint32 perms)
+ {
+     uint32        tbl_perms = 0;
+
+     tbl_perms |= (perms & DB_COLUMN__USE ? DB_TABLE__USE : 0);
+     tbl_perms |= (perms & DB_COLUMN__SELECT ? DB_TABLE__SELECT : 0);
+     tbl_perms |= (perms & DB_COLUMN__INSERT ? DB_TABLE__INSERT : 0);
+     tbl_perms |= (perms & DB_COLUMN__UPDATE ? DB_TABLE__UPDATE : 0);
+     selist = addEvalRelationRTE(selist, rte, tbl_perms);
+
+     /*
+      * Special care for pg_largeobject.data
+      */
+     if ((perms & DB_COLUMN__SELECT) != 0 &&
+         rte->relid == LargeObjectRelationId &&
+         attno == Anum_pg_largeobject_data)
+         rte->pgaceTuplePerms |= SEPGSQL_PERMS_READ;
+
+     return addEvalAttribute(selist, rte->relid, rte->inh, attno, perms);
+ }
+
+ /*
+  * addEvalForeignKeyConstraint
+  *
+  * This function add special case handling for PK/FK constraints.
+  * invoke trigger function requires to access rights for all attribute
+  *
+  */
+ static List *
+ addEvalForeignKeyConstraint(List *selist, Form_pg_trigger trigger)
+ {
+     HeapTuple contup;
+     Datum attdat;
+     ArrayType *attrs;
+     int index;
+     int16 *attnum;
+     bool isnull;
+
+     contup = SearchSysCache(CONSTROID,
+                             ObjectIdGetDatum(trigger->tgconstraint),
+                             0, 0, 0);
+     if (!HeapTupleIsValid(contup))
+         elog(ERROR, "SELinux: cache lookup failed for constraint %u",
+              trigger->tgconstrrelid);
+
+     if (trigger->tgfoid == F_RI_FKEY_CHECK_INS ||
+         trigger->tgfoid == F_RI_FKEY_CHECK_UPD)
+         attdat = SysCacheGetAttr(CONSTROID, contup,
+                                  Anum_pg_constraint_conkey, &isnull);
+     else
+         attdat = SysCacheGetAttr(CONSTROID, contup,
+                                  Anum_pg_constraint_confkey, &isnull);
+     if (isnull)
+         elog(ERROR, "null PK/FK for constraint %u",
+              trigger->tgconstrrelid);
+     attrs = DatumGetArrayTypeP(attdat);
+
+     if (ARR_NDIM(attrs) != 1 ||
+         ARR_HASNULL(attrs) ||
+         ARR_ELEMTYPE(attrs) != INT2OID)
+         elog(ERROR, "SELinux: unexpected constraint %u", trigger->tgconstrrelid);
+
+     attnum = (int16 *) ARR_DATA_PTR(attrs);
+     for (index = 0; index < ARR_DIMS(attrs)[0]; index++)
+         selist = addEvalAttribute(selist, trigger->tgrelid, false,
+                                   attnum[index], DB_COLUMN__SELECT);
+
+     ReleaseSysCache(contup);
+
+     return selist;
+ }
+
+ /*
+  * addEvalTriggerFunction
+  *
+  * This function adds needed items into selist, to execute a trigger
+  * function. At least, it requires permission set to execute a function
+  * configured as a trigger, to select a table and whole of columns
+  * because whole of a tuple is delivered to trigger functions.
+  */
+ static List *
+ addEvalTriggerFunction(List *selist, Oid relid, int cmdType)
+ {
+     Relation    rel;
+     SysScanDesc scan;
+     ScanKeyData skey;
+     HeapTuple    tuple;
+
+     rel = heap_open(TriggerRelationId, AccessShareLock);
+     ScanKeyInit(&skey,
+                 Anum_pg_trigger_tgrelid,
+                 BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid));
+     scan = systable_beginscan(rel, TriggerRelidNameIndexId,
+                               true, SnapshotNow, 1, &skey);
+     while (HeapTupleIsValid((tuple = systable_getnext(scan))))
+     {
+         Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
+         Form_pg_class relForm;
+         HeapTuple reltup;
+
+         /*
+          * Skip not-invoked triggers
+          */
+         if (!trigForm->tgenabled)
+             continue;
+         if (cmdType == CMD_INSERT && !TRIGGER_FOR_INSERT(trigForm->tgtype))
+             continue;
+         if (cmdType == CMD_UPDATE && !TRIGGER_FOR_UPDATE(trigForm->tgtype))
+             continue;
+         if (cmdType == CMD_DELETE && !TRIGGER_FOR_DELETE(trigForm->tgtype))
+             continue;
+
+         /*
+          * per STATEMENT trigger cannot refer whole of a tuple
+          */
+         if (!TRIGGER_FOR_ROW(trigForm->tgtype))
+             continue;
+
+         /*
+          * BEFORE-ROW-INSERT trigger cannot refer whole of a tuple
+          */
+         if (TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
+             TRIGGER_FOR_INSERT(trigForm->tgtype))
+             continue;
+
+         reltup = SearchSysCache(RELOID,
+                                 ObjectIdGetDatum(relid),
+                                 0, 0, 0);
+         relForm = (Form_pg_class) GETSTRUCT(reltup);
+
+         selist = addEvalRelation(selist, relid, false, DB_TABLE__SELECT);
+
+         if (RI_FKey_trigger_type(trigForm->tgfoid) != RI_TRIGGER_NONE)
+             selist = addEvalForeignKeyConstraint(selist, trigForm);
+         else
+             selist = addEvalAttribute(selist, relid, false,
+                                       0, DB_COLUMN__SELECT);
+         ReleaseSysCache(reltup);
+     }
+     systable_endscan(scan);
+     heap_close(rel, AccessShareLock);
+
+     return selist;
+ }
+
+ /*
+  * sepgsqlExprWalker
+  *
+  * This function walks on the given expression tree to pick up
+  * all the appeared tables and columns. Their identifiers are
+  * chains on swc->selist to evaluate permissions on them later.
+  *
+  * walkVarHelper picks up an accessed column and its contained
+  * table, and chains them on swc->selist.
+  * When swc->is_internal_use is true, it means this reference
+  * is checked as "use" permission because its contents are
+  * consumed internally, and not to be returned to client directly.
+  * Otherwise, "select" permission is applied.
+  *
+  * walkQueryHelper walks on Query structure.
+  * The reason why we don't use query_tree_walker() is that
+  * SE-PostgreSQL need to apply different permission between
+  * targetList and havingQual, for example.
+  */
+
+ static bool
+ sepgsqlExprWalker(Node *node, sepgsqlWalkerContext *swc);
+
+ static void
+ sepgsqlExprWalkerFlags(Node *node, sepgsqlWalkerContext *swc,
+                        bool is_internal_use);
+
+ /*
+  * wholeRefJoinWalker
+  *
+  * A corner case need to invoke this walker function.
+  * When we use whole-row-reference on RTE_JOIN relation,
+  * it should be extracted to whole-row-references on
+  * sources relations.
+  *
+  * EXAMPLE:
+  *   SELECT t4 FROM (t1 JOIN (t2 JOIN t3 USING (a)) USING (b)) AS t4;
+  *
+  * Because RangeTblEntry with RTE_JOIN does not have any identifiers
+  * of its source relations, we have to scan Query->jointree again to
+  * look up sources again. :(
+  */
+ typedef struct
+ {
+     Query *query;
+     int rtindex;
+     /*
+      * rtindex == 0 means we are now walking on the required JoinExpr
+      * or its leafs, so we need to pick up all the appeared relations
+      * under the JoinExpr in this case.
+      */
+     List *selist;
+     uint32 perms;
+ } wholeRefJoinWalkerContext;
+
+ static bool
+ wholeRefJoinWalker(Node *node, wholeRefJoinWalkerContext *jwc)
+ {
+     if (!node)
+         return false;
+
+     if (IsA(node, JoinExpr))
+     {
+         JoinExpr *j = (JoinExpr *) node;
+
+         if (j->rtindex == jwc->rtindex)
+         {
+             int rtindex_backup = jwc->rtindex;
+             bool rc;
+
+             jwc->rtindex = 0;
+             rc = expression_tree_walker(node, wholeRefJoinWalker, jwc);
+             jwc->rtindex = rtindex_backup;
+
+             return rc;
+         }
+     }
+     else if (IsA(node, RangeTblRef) && jwc->rtindex == 0)
+     {
+         RangeTblRef *rtr = (RangeTblRef *) node;
+         RangeTblEntry *rte = rt_fetch(rtr->rtindex,
+                                       jwc->query->rtable);
+         if (rte->rtekind == RTE_RELATION)
+         {
+             jwc->selist = addEvalAttributeRTE(jwc->selist, rte, 0, jwc->perms);
+         }
+     }
+     return expression_tree_walker(node, wholeRefJoinWalker, jwc);
+ }
+
+ static void
+ walkVarHelper(Var *var, sepgsqlWalkerContext *swc)
+ {
+     sepgsqlWalkerContext *cur = swc;
+     Query           *query;
+     RangeTblEntry  *rte;
+     int                lv;
+
+     Assert(IsA(var, Var));
+
+     for (lv = var->varlevelsup; lv > 0; lv--)
+     {
+         Assert(cur->parent != NULL);
+         cur = cur->parent;
+     }
+     query = cur->query;
+
+     rte = rt_fetch(var->varno, query->rtable);
+     Assert(IsA(rte, RangeTblEntry));
+
+     if (rte->rtekind == RTE_RELATION)
+     {
+         uint32 perms = swc->is_internal_use
+             ? DB_COLUMN__USE : DB_COLUMN__SELECT;
+
+         swc->selist = addEvalAttributeRTE(swc->selist, rte,
+                                           var->varattno, perms);
+     }
+     else if (rte->rtekind == RTE_JOIN)
+     {
+         if (var->varattno == 0)
+         {
+             wholeRefJoinWalkerContext jwcData;
+
+             jwcData.query = query;
+             jwcData.rtindex = var->varno;
+             jwcData.selist = swc->selist;
+             jwcData.perms = swc->is_internal_use
+                 ? DB_COLUMN__USE : DB_COLUMN__SELECT;
+
+             wholeRefJoinWalker((Node *)query->jointree, &jwcData);
+             swc->selist = jwcData.selist;
+         }
+         else
+         {
+             Node *node = list_nth(rte->joinaliasvars,
+                                   var->varattno - 1);
+             sepgsqlExprWalker(node, swc);
+         }
+     }
+ }
+
+ static List *
+ walkQueryHelper(Query *query, sepgsqlWalkerContext *swc)
+ {
+     sepgsqlWalkerContext swcData;
+     RangeTblEntry *rte;
+
+     memset(&swcData, 0, sizeof(swcData));
+     swcData.parent = swc;
+     swcData.selist = (!swc ? NIL : swc->selist);
+     swcData.query = query;
+
+     if (query->commandType != CMD_DELETE)
+     {
+         ListCell *l;
+
+         foreach (l, query->targetList)
+         {
+             TargetEntry *tle = lfirst(l);
+             bool is_security = false;
+
+             Assert(IsA(tle, TargetEntry));
+
+             if (tle->resjunk &&
+                 tle->resname &&
+                 strcmp(tle->resname, SecurityLabelAttributeName) == 0)
+                 is_security = true;
+
+             if (tle->resjunk && !is_security)
+             {
+                 sepgsqlExprWalkerFlags((Node *) tle->expr, &swcData, true);
+                 continue;
+             }
+
+             sepgsqlExprWalkerFlags((Node *) tle->expr, &swcData, false);
+
+             if (query->commandType != CMD_SELECT)
+             {
+                 AttrNumber attno = tle->resno;
+                 uint32 perms;
+
+                 if (is_security)
+                     attno = SecurityLabelAttributeNumber;
+
+                 if (query->commandType == CMD_UPDATE)
+                     perms = DB_COLUMN__UPDATE;
+                 else
+                     perms = DB_COLUMN__INSERT;
+
+                 rte = rt_fetch(query->resultRelation, query->rtable);
+                 Assert(IsA(rte, RangeTblEntry));
+
+                 swcData.selist
+                     = addEvalAttributeRTE(swcData.selist, rte, attno, perms);
+             }
+         }
+     }
+     else
+     {
+         /* no need to check column-level permission for DELETE */
+         rte = rt_fetch(query->resultRelation, query->rtable);
+         Assert(IsA(rte, RangeTblEntry));
+
+         swcData.selist
+             = addEvalRelationRTE(swcData.selist, rte, DB_TABLE__DELETE);
+     }
+
+     sepgsqlExprWalkerFlags((Node *) query->returningList, &swcData, false);
+     sepgsqlExprWalkerFlags((Node *) query->jointree, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->setOperations, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->havingQual, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->sortClause, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->groupClause, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->limitOffset, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->limitCount, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->cteList, &swcData, true);
+     sepgsqlExprWalkerFlags((Node *) query->windowClause, &swcData, true);
+
+     return swcData.selist;
+ }
+
+ static void
+ walkRangeTblRefHelper(RangeTblRef *rtr, sepgsqlWalkerContext *swc)
+ {
+     Query *query = swc->query;
+     RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
+
+     Assert(IsA(rte, RangeTblEntry));
+
+     switch (rte->rtekind)
+     {
+     case RTE_RELATION:
+         if (rtr->rtindex != query->resultRelation)
+             swc->selist = addEvalRelationRTE(swc->selist, rte,
+                                              DB_TABLE__SELECT);
+         break;
+
+     case RTE_SUBQUERY:
+         swc->selist = walkQueryHelper(rte->subquery, swc);
+         break;
+
+     case RTE_FUNCTION:
+         sepgsqlExprWalker(rte->funcexpr, swc);
+         break;
+
+     case RTE_VALUES:
+         sepgsqlExprWalker((Node *) rte->values_lists, swc);
+         break;
+
+     default:
+         /* do nothing */
+         break;
+     }
+ }
+
+ static void
+ walkSortGroupClauseHelper(SortGroupClause *sgc, sepgsqlWalkerContext *swc)
+ {
+     Query *query = swc->query;
+     TargetEntry *tle
+         = get_sortgroupref_tle(sgc->tleSortGroupRef,
+                                query->targetList);
+
+     Assert(IsA(tle, TargetEntry));
+
+     sepgsqlExprWalker((Node *) tle->expr, swc);
+ }
+
+ static bool
+ sepgsqlExprWalker(Node *node, sepgsqlWalkerContext *swc)
+ {
+     if (node == NULL)
+         return false;
+     else if (IsA(node, Var))
+         walkVarHelper((Var *) node, swc);
+     else if (IsA(node, RangeTblRef))
+         walkRangeTblRefHelper((RangeTblRef *) node, swc);
+     else if (IsA(node, Query))
+     {
+         swc->selist
+             = walkQueryHelper((Query *) node, swc);
+     }
+     else if (IsA(node, SortGroupClause))
+     {
+         walkSortGroupClauseHelper((SortGroupClause *) node, swc);
+
+         return false;
+     }
+     return expression_tree_walker(node, sepgsqlExprWalker, (void *) swc);
+ }
+
+ static void
+ sepgsqlExprWalkerFlags(Node *node, sepgsqlWalkerContext *swc,
+                        bool is_internal_use)
+ {
+     bool        saved_is_internal_use = swc->is_internal_use;
+
+     swc->is_internal_use = is_internal_use;
+     sepgsqlExprWalker(node, swc);
+     swc->is_internal_use = saved_is_internal_use;
+ }
+
+ /*
+  * sepgsqlPostQueryRewrite
+  *
+  * This function is invoked just after given queries are rewritten
+  * via query-rewritter phase. It walks on given query trees to
+  * picks up all appeared tables and columns, and to chains the list
+  * of them on query->pgaceItem.
+  * This list is used to evaluate permissions later, just before
+  * the query execution.
+  *
+  * It do nothing for DDL queries, because these are processed in
+  * sepgsqlProcessUtility() hook.
+  */
+ List *
+ sepgsqlPostQueryRewrite(List *queryList)
+ {
+     ListCell   *l;
+
+     foreach (l, queryList)
+     {
+         Query  *query = (Query *) lfirst(l);
+
+         Assert(IsA(query, Query));
+
+         if (query->commandType == CMD_SELECT ||
+             query->commandType == CMD_UPDATE ||
+             query->commandType == CMD_INSERT ||
+             query->commandType == CMD_DELETE)
+         {
+             query->pgaceItem
+                 = (Node *) walkQueryHelper(query, NULL);
+         }
+     }
+
+     return queryList;
+ }
+
+ /*
+  * checkSelinuxEvalItem
+  *   checks give SelinuxEvalItem object based on the security
+  *   policy of SELinux.
+  */
+ static void
+ checkSelinuxEvalItem(SelinuxEvalItem *seitem)
+ {
+     Form_pg_class relForm;
+     Form_pg_attribute attForm;
+     HeapTuple tuple;
+     AttrNumber attno;
+     const char *audit_name;
+     int index;
+
+     Assert(IsA(seitem, SelinuxEvalItem));
+
+     /*
+      * Prevent to write pg_security by hand
+      */
+     if (seitem->relid == SecurityRelationId &&
+         (seitem->relperms & (DB_TABLE__UPDATE | DB_TABLE__INSERT | DB_TABLE__DELETE)))
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not modify pg_security by hand")));
+
+     /*
+      * Permission checks on table
+      */
+     tuple = SearchSysCache(RELOID,
+                            ObjectIdGetDatum(seitem->relid),
+                            0, 0, 0);
+     if (!HeapTupleIsValid(tuple))
+         elog(ERROR, "SELinux: cache lookup failed for relation: %u",
+              seitem->relid);
+     relForm = (Form_pg_class) GETSTRUCT(tuple);
+     if (relForm->relkind != RELKIND_RELATION)
+     {
+         ReleaseSysCache(tuple);
+         return;
+     }
+
+     audit_name = sepgsqlTupleName(RelationRelationId, tuple);
+     sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                SECCLASS_DB_TABLE,
+                                seitem->relperms,
+                                audit_name);
+     ReleaseSysCache(tuple);
+
+     /*
+      * Expand whole-row-reference
+      */
+     index = seitem_attno_to_index(InvalidAttrNumber);
+     if (seitem->attperms[index] != 0)
+     {
+         uint32 perms = seitem->attperms[index];
+
+         seitem->attperms[index] = 0;
+         for (index++; index < seitem->nattrs; index++)
+             seitem->attperms[index] |= perms;
+     }
+
+     /*
+      * Permission checks on columns
+      */
+     for (index = 0; index < seitem->nattrs; index++)
+     {
+         if (seitem->attperms[index] == 0)
+             continue;
+
+         attno = seitem_index_to_attno(index);
+         tuple = SearchSysCache(ATTNUM,
+                                ObjectIdGetDatum(seitem->relid),
+                                Int16GetDatum(attno),
+                                0, 0);
+         if (!HeapTupleIsValid(tuple))
+             elog(ERROR, "SELinux: cache lookup failed for attribute %d of relation %u",
+                  attno, seitem->relid);
+         attForm = (Form_pg_attribute) GETSTRUCT(tuple);
+         /*
+          * NOTE: When user uses whole-row-reference on a table
+          * which has already dropped column, the column can have
+          * non-zero required permissions, but being ignorable.
+          */
+         if (attForm->attisdropped)
+         {
+             ReleaseSysCache(tuple);
+             continue;
+         }
+
+         audit_name = sepgsqlTupleName(AttributeRelationId, tuple);
+         sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple),
+                                    SECCLASS_DB_COLUMN,
+                                    seitem->attperms[index],
+                                    audit_name);
+         ReleaseSysCache(tuple);
+     }
+ }
+
+ static List *
+ expandEvalItemInheritance(List *selist)
+ {
+     List       *result = NIL;
+     List       *inherits;
+     ListCell   *l, *i;
+     int index;
+
+     foreach (l, selist)
+     {
+         SelinuxEvalItem *seitem = lfirst(l);
+
+         Assert(IsA(seitem, SelinuxEvalItem));
+
+         if (!seitem->inh)
+         {
+             result = lappend(result, seitem);
+             continue;
+         }
+
+         inherits = find_all_inheritors(seitem->relid);
+         foreach (i, inherits)
+         {
+             result = addEvalRelation(result, lfirst_oid(i), false,
+                                      seitem->relperms);
+             for (index = 0; index < seitem->nattrs; index++)
+             {
+                 Oid relid_inh = lfirst_oid(i);
+                 AttrNumber attno;
+
+                 if (seitem->attperms[index] == 0)
+                     continue;
+
+                 attno = seitem_index_to_attno(index);
+                 if (attno < 1 || seitem->relid == relid_inh)
+                 {
+                     /*
+                      * If attribute is system-column or whole-row-reference,
+                      * or inherit relation is itself, we don't need to fix up
+                      * attribute number.
+                      */
+                     result = addEvalAttribute(result, relid_inh, false,
+                                               attno, seitem->attperms[index]);
+                     continue;
+                 }
+                 else
+                 {
+                     char *attname = get_attname(seitem->relid, attno);
+
+                     if (!attname)
+                         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+                              attno, seitem->relid);
+
+                     attno = get_attnum(relid_inh, attname);
+                     if (attno == InvalidAttrNumber)
+                         elog(ERROR, "cache lookup failed for attribute %s of relation %u",
+                              attname, relid_inh);
+
+                     result = addEvalAttribute(result, relid_inh, false,
+                                               attno, seitem->attperms[index]);
+                     pfree(attname);
+                 }
+             }
+         }
+     }
+     return result;
+ }
+
+ /*
+  * sepgsqlExecutorStart
+  *
+  * This function is invoked at the head of ExecutorStart, to evaluate
+  * permissions to access appeared object within the given query.
+  * Query->pgaceItem is a list of SelinuxEvalItem objects generated in
+  * previous phase, and it is copied to PlannedStmt->pgaceItem in the
+  * optimizer.
+  * This functions expand given selist based on table inheritance,
+  * adds additional permissions related to trigger functions, and
+  * expands whole-row-references. Then, these items are evaluated
+  * based on the security policy of SELinux.
+  */
+ void
+ sepgsqlExecutorStart(QueryDesc *queryDesc, int eflags)
+ {
+     PlannedStmt *pstmt = queryDesc->plannedstmt;
+     RangeTblEntry *rte;
+     List       *selist;
+     ListCell   *l;
+
+     /*
+      * EXPLAIN statement does not access any object.
+      */
+     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
+         return;
+
+     if (!pstmt->pgaceItem)
+         return;
+
+     Assert(IsA(pstmt->pgaceItem, List));
+     selist = copyObject(pstmt->pgaceItem);
+
+     /*
+      * expand table inheritances
+      */
+     selist = expandEvalItemInheritance(selist);
+
+     /*
+      * add checks for access via trigger function
+      */
+     foreach(l, pstmt->resultRelations)
+     {
+         Index        rindex = lfirst_int(l);
+
+         rte = rt_fetch(rindex, pstmt->rtable);
+         Assert(IsA(rte, RangeTblEntry));
+
+         selist = addEvalTriggerFunction(selist, rte->relid,
+                                         pstmt->commandType);
+     }
+
+     /*
+      * Check SelinuxEvalItem
+      */
+     foreach (l, selist)
+         checkSelinuxEvalItem((SelinuxEvalItem *) lfirst(l));
+ }
+
+ /*
+  * --------------------------------------------------------------
+  * Process Utility hooks
+  * --------------------------------------------------------------
+  */
+
+ /*
+  * sepgsqlProcessUtility
+  *
+  * This function is invoked from the head of ProcessUtility(), and
+  * checks given DDL queries.
+  * SE-PostgreSQL catch most of DDL actions on HeapTuple hooks, but
+  * an exception is TRUNCATE statement.
+  */
+ void
+ sepgsqlProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel)
+ {
+     switch (nodeTag(parsetree))
+     {
+     case T_LoadStmt:
+         {
+             LoadStmt *load = (LoadStmt *)parsetree;
+             sepgsqlCheckModuleInstallPerms(load->filename);
+         }
+         break;
+
+     case T_CreateFdwStmt:
+         {
+             CreateFdwStmt *createFdw = (CreateFdwStmt *)parsetree;
+             sepgsqlCheckModuleInstallPerms(createFdw->library);
+         }
+         break;
+
+     case T_AlterFdwStmt:
+         {
+             AlterFdwStmt *alterFdw = (AlterFdwStmt *)parsetree;
+             if (alterFdw->library)
+                 sepgsqlCheckModuleInstallPerms(alterFdw->library);
+         }
+         break;
+
+     default:
+         /*
+          * do nothing here
+          */
+         break;
+     }
+ }
+
+ /* ----------------------------------------------------------
+  * COPY TO/COPY FROM statement hooks
+  * ---------------------------------------------------------- */
+
+ /*
+  * sepgsqlCopyTable
+  *
+  * This function checks permission on the target table and columns
+  * of COPY statement. We don't place it at sepgsql/hooks.c because
+  * it internally uses addEvalXXXX() interface statically declared.
+  */
+ void
+ sepgsqlCopyTable(Relation rel, List *attNumList, bool isFrom)
+ {
+     List       *selist = NIL;
+     ListCell   *l;
+
+     /*
+      * on 'COPY FROM SELECT ...' cases, any checkings are done in select.c
+      */
+     if (rel == NULL)
+         return;
+
+     /*
+      * no need to check non-table relation
+      */
+     if (RelationGetForm(rel)->relkind != RELKIND_RELATION)
+         return;
+
+     selist = addEvalRelation(selist, RelationGetRelid(rel), false,
+                              isFrom ? DB_TABLE__INSERT : DB_TABLE__SELECT);
+     foreach(l, attNumList)
+     {
+         AttrNumber    attnum = lfirst_int(l);
+
+         selist = addEvalAttribute(selist, RelationGetRelid(rel), false, attnum,
+                                   isFrom ? DB_COLUMN__INSERT : DB_COLUMN__SELECT);
+     }
+
+     /*
+      * check call trigger function
+      */
+     if (isFrom)
+         selist = addEvalTriggerFunction(selist, RelationGetRelid(rel), CMD_INSERT);
+
+     foreach (l, selist)
+         checkSelinuxEvalItem((SelinuxEvalItem *) lfirst(l));
+ }
+
+ /*
+  * sepgsqlCopyFile
+  *
+  * This function check permission whether the client can
+  * read from/write to the given file.
+  */
+ void sepgsqlCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom)
+ {
+     security_context_t context;
+     security_class_t tclass
+         = sepgsqlFileObjectClass(fdesc, filename);
+
+     if (fgetfilecon_raw(fdesc, &context) < 0)
+         ereport(ERROR,
+                 (errcode(ERRCODE_SELINUX_ERROR),
+                  errmsg("SELinux: could not get context of %s", filename)));
+     PG_TRY();
+     {
+         sepgsqlComputePermission(sepgsqlGetClientContext(),
+                                  context,
+                                  tclass,
+                                  isFrom ? FILE__READ : FILE__WRITE,
+                                  filename);
+     }
+     PG_CATCH();
+     {
+         freecon(context);
+         PG_RE_THROW();
+     }
+     PG_END_TRY();
+     freecon(context);
+ }
+
+ /*
+  * sepgsqlCopyToTuple
+  *
+  * This function check permission to read the given tuple.
+  * If not allowed to read, it returns false to skip COPY TO
+  * this tuple. In the result, any violated tuples are filtered
+  * from the result of COPY TO, as if these are not exist.
+  */
+ bool
+ sepgsqlCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple)
+ {
+     uint32        perms = SEPGSQL_PERMS_SELECT;
+
+     /*
+      * for 'pg_largeobject'
+      */
+     if (RelationGetRelid(rel) == LargeObjectRelationId)
+     {
+         ListCell   *l;
+
+         foreach(l, attNumList)
+         {
+             AttrNumber    attnum = lfirst_int(l);
+
+             if (attnum == Anum_pg_largeobject_data)
+             {
+                 perms |= SEPGSQL_PERMS_READ;
+                 break;
+             }
+         }
+     }
+     return sepgsqlCheckTuplePerms(rel, tuple, NULL, perms, false);
+ }
diff -Nrpc base/src/backend/storage/file/fd.c sepgsql/src/backend/storage/file/fd.c
*** base/src/backend/storage/file/fd.c    Tue Jan 13 09:22:28 2009
--- sepgsql/src/backend/storage/file/fd.c    Tue Jan 13 09:39:35 2009
*************** FileTruncate(File file, off_t offset)
*** 1291,1296 ****
--- 1291,1303 ----
      return returnCode;
  }

+ int
+ FileRawDescriptor(File file)
+ {
+     Assert(FileIsValid(file));
+
+     return VfdCache[file].fd;
+ }

  /*
   * Routines that want to use stdio (ie, FILE*) should use AllocateFile
diff -Nrpc base/src/backend/storage/ipc/ipci.c sepgsql/src/backend/storage/ipc/ipci.c
*** base/src/backend/storage/ipc/ipci.c    Mon Jan  5 17:36:07 2009
--- sepgsql/src/backend/storage/ipc/ipci.c    Mon Jan  5 17:41:04 2009
***************
*** 25,30 ****
--- 25,31 ----
  #include "postmaster/autovacuum.h"
  #include "postmaster/bgwriter.h"
  #include "postmaster/postmaster.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/ipc.h"
  #include "storage/pg_shmem.h"
*************** CreateSharedMemoryAndSemaphores(bool mak
*** 118,123 ****
--- 119,125 ----
  #ifdef EXEC_BACKEND
          size = add_size(size, ShmemBackendArraySize());
  #endif
+         size = add_size(size, pgaceShmemSize());

          /* freeze the addin request size and include it */
          addin_request_allowed = false;
diff -Nrpc base/src/backend/tcop/fastpath.c sepgsql/src/backend/tcop/fastpath.c
*** base/src/backend/tcop/fastpath.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/tcop/fastpath.c    Fri Jan 16 17:05:27 2009
***************
*** 28,33 ****
--- 28,34 ----
  #include "miscadmin.h"
  #include "tcop/fastpath.h"
  #include "tcop/tcopprot.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/lsyscache.h"
  #include "utils/snapmgr.h"
*************** HandleFunctionRequest(StringInfo msgBuf)
*** 348,353 ****
--- 349,355 ----
      if (aclresult != ACLCHECK_OK)
          aclcheck_error(aclresult, ACL_KIND_PROC,
                         get_func_name(fid));
+     pgaceCallFunction(&fip->flinfo);

      /*
       * Prepare function call info block and insert arguments.
diff -Nrpc base/src/backend/tcop/pquery.c sepgsql/src/backend/tcop/pquery.c
*** base/src/backend/tcop/pquery.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/tcop/pquery.c    Sat Jan  3 15:58:18 2009
*************** PortalStart(Portal portal, ParamListInfo
*** 573,579 ****
                      Assert(pstmt->returningLists);
                      portal->tupDesc =
                          ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
!                                             false);
                  }

                  /*
--- 573,579 ----
                      Assert(pstmt->returningLists);
                      portal->tupDesc =
                          ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
!                                             false, false, false);
                  }

                  /*
diff -Nrpc base/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c
*** base/src/backend/tcop/utility.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/tcop/utility.c    Fri Jan 23 10:55:35 2009
***************
*** 49,54 ****
--- 49,55 ----
  #include "postmaster/bgwriter.h"
  #include "rewrite/rewriteDefine.h"
  #include "rewrite/rewriteRemove.h"
+ #include "security/pgace.h"
  #include "storage/fd.h"
  #include "tcop/pquery.h"
  #include "tcop/utility.h"
*************** ProcessUtility(Node *parsetree,
*** 258,263 ****
--- 259,266 ----
      if (completionTag)
          completionTag[0] = '\0';

+     pgaceProcessUtility(parsetree, params, isTopLevel);
+
      switch (nodeTag(parsetree))
      {
              /*
diff -Nrpc base/src/backend/utils/adt/acl.c sepgsql/src/backend/utils/adt/acl.c
*** base/src/backend/utils/adt/acl.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/utils/adt/acl.c    Fri Jan 23 10:55:35 2009
*************** static List *cached_membership_roles = N
*** 66,73 ****

  static const char *getid(const char *s, char *n);
  static void putid(char *p, const char *s);
- static Acl *allocacl(int n);
- static void check_acl(const Acl *acl);
  static const char *aclparse(const char *s, AclItem *aip);
  static bool aclitem_match(const AclItem *a1, const AclItem *a2);
  static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
--- 66,71 ----
*************** aclparse(const char *s, AclItem *aip)
*** 347,353 ****
   * RETURNS:
   *        the new Acl
   */
! static Acl *
  allocacl(int n)
  {
      Acl           *new_acl;
--- 345,351 ----
   * RETURNS:
   *        the new Acl
   */
! Acl *
  allocacl(int n)
  {
      Acl           *new_acl;
*************** aclconcat(const Acl *left_acl, const Acl
*** 410,416 ****
  /*
   * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
   */
! static void
  check_acl(const Acl *acl)
  {
      if (ARR_ELEMTYPE(acl) != ACLITEMOID)
--- 408,414 ----
  /*
   * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
   */
! void
  check_acl(const Acl *acl)
  {
      if (ARR_ELEMTYPE(acl) != ACLITEMOID)
diff -Nrpc base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c
*** base/src/backend/utils/adt/ri_triggers.c    Fri Jan  9 10:09:59 2009
--- sepgsql/src/backend/utils/adt/ri_triggers.c    Fri Jan  9 10:15:15 2009
***************
*** 39,44 ****
--- 39,45 ----
  #include "parser/parse_coerce.h"
  #include "parser/parse_relation.h"
  #include "miscadmin.h"
+ #include "security/pgace.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/fmgroids.h"
*************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl
*** 3264,3269 ****
--- 3265,3272 ----
      int            spi_result;
      Oid            save_userid;
      bool        save_secdefcxt;
+     Datum        rowacl_private = 0;
+     Datum        pgace_private = 0;
      Datum        vals[RI_MAX_NUMKEYS * 2];
      char        nulls[RI_MAX_NUMKEYS * 2];

*************** ri_PerformCheck(RI_QueryKey *qkey, SPIPl
*** 3346,3356 ****
      GetUserIdAndContext(&save_userid, &save_secdefcxt);
      SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true);

!     /* Finally we can run the query. */
!     spi_result = SPI_execute_snapshot(qplan,
!                                       vals, nulls,
!                                       test_snapshot, crosscheck_snapshot,
!                                       false, false, limit);

      /* Restore UID */
      SetUserIdAndContext(save_userid, save_secdefcxt);
--- 3349,3371 ----
      GetUserIdAndContext(&save_userid, &save_secdefcxt);
      SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true);

!     pgaceBeginPerformCheckFK(query_rel, detectNewRows, save_userid,
!                              &rowacl_private, &pgace_private);
!     PG_TRY();
!     {
!         /* Finally we can run the query. */
!         spi_result = SPI_execute_snapshot(qplan,
!                                           vals, nulls,
!                                           test_snapshot, crosscheck_snapshot,
!                                           false, false, limit);
!     }
!     PG_CATCH();
!     {
!         pgaceEndPerformCheckFK(query_rel, rowacl_private, pgace_private);
!         PG_RE_THROW();
!     }
!     PG_END_TRY();
!     pgaceEndPerformCheckFK(query_rel, rowacl_private, pgace_private);

      /* Restore UID */
      SetUserIdAndContext(save_userid, save_secdefcxt);
diff -Nrpc base/src/backend/utils/adt/trigfuncs.c sepgsql/src/backend/utils/adt/trigfuncs.c
*** base/src/backend/utils/adt/trigfuncs.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/utils/adt/trigfuncs.c    Sat Jan  3 15:58:18 2009
*************** suppress_redundant_updates_trigger(PG_FU
*** 62,78 ****
      newheader = newtuple->t_data;
      oldheader = oldtuple->t_data;

-     /*
-      * We are called before the OID, if any, has been transcribed from the
-      * old tuple to the new (in heap_update).  To avoid a bogus compare
-      * failure, copy the OID now.  But check that someone didn't already put
-      * another OID value into newtuple.  (That's not actually possible at
-      * present, but maybe someday.)
-      */
-      if (trigdata->tg_relation->rd_rel->relhasoids &&
-         !OidIsValid(HeapTupleHeaderGetOid(newheader)))
-         HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader));
-
      /* if the tuple payload is the same ... */
      if (newtuple->t_len == oldtuple->t_len &&
          newheader->t_hoff == oldheader->t_hoff &&
--- 62,67 ----
diff -Nrpc base/src/backend/utils/cache/catcache.c sepgsql/src/backend/utils/cache/catcache.c
*** base/src/backend/utils/cache/catcache.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/utils/cache/catcache.c    Fri Jan 16 17:05:27 2009
*************** ReleaseCatCache(HeapTuple tuple)
*** 1316,1321 ****
--- 1316,1353 ----
          CatCacheRemoveCTup(ct->my_cache, ct);
  }

+ /*
+  * InsertCatCache
+  *
+  * This function enables to refer a tuple recently inserted, using catcache
+  * until next CommandCounterIncrement.
+  */
+ void InsertCatCache(CatCache *cache, HeapTuple tuple)
+ {
+     ScanKeyData skey[4];
+     uint32 hashValue;
+     Index hashIndex;
+     bool isnull;
+     int i;
+
+     /* initialize the search key information */
+     memcpy(skey, cache->cc_skey, sizeof(skey));
+     for (i=0; i < cache->cc_nkeys; i++)
+     {
+         skey[i].sk_argument = heap_getattr(tuple, cache->cc_key[i],
+                                            cache->cc_tupdesc, &isnull);
+         Assert(!isnull);
+     }
+
+     /* find the hash bucket in which to look for the tuple */
+     if (cache->cc_tupdesc == NULL)
+         CatalogCacheInitializeCache(cache);
+     hashValue = CatalogCacheComputeHashValue(cache, cache->cc_nkeys, skey);
+     hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
+
+     /* Insert a new tuple */
+     CatalogCacheCreateEntry(cache, tuple, hashValue, hashIndex, false);
+ }

  /*
   *    SearchCatCacheList
diff -Nrpc base/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/cache/plancache.c
*** base/src/backend/utils/cache/plancache.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/utils/cache/plancache.c    Sat Jan  3 15:58:18 2009
*************** PlanCacheComputeResultDesc(List *stmt_li
*** 847,858 ****
              if (IsA(node, Query))
              {
                  query = (Query *) node;
!                 return ExecCleanTypeFromTL(query->targetList, false);
              }
              if (IsA(node, PlannedStmt))
              {
                  pstmt = (PlannedStmt *) node;
!                 return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false);
              }
              /* other cases shouldn't happen, but return NULL */
              break;
--- 847,860 ----
              if (IsA(node, Query))
              {
                  query = (Query *) node;
!                 return ExecCleanTypeFromTL(query->targetList,
!                                            false, false, false);
              }
              if (IsA(node, PlannedStmt))
              {
                  pstmt = (PlannedStmt *) node;
!                 return ExecCleanTypeFromTL(pstmt->planTree->targetlist,
!                                            false, false, false);
              }
              /* other cases shouldn't happen, but return NULL */
              break;
*************** PlanCacheComputeResultDesc(List *stmt_li
*** 863,875 ****
              {
                  query = (Query *) node;
                  Assert(query->returningList);
!                 return ExecCleanTypeFromTL(query->returningList, false);
              }
              if (IsA(node, PlannedStmt))
              {
                  pstmt = (PlannedStmt *) node;
                  Assert(pstmt->returningLists);
!                 return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false);
              }
              /* other cases shouldn't happen, but return NULL */
              break;
--- 865,879 ----
              {
                  query = (Query *) node;
                  Assert(query->returningList);
!                 return ExecCleanTypeFromTL(query->returningList,
!                                            false, false, false);
              }
              if (IsA(node, PlannedStmt))
              {
                  pstmt = (PlannedStmt *) node;
                  Assert(pstmt->returningLists);
!                 return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
!                                            false, false, false);
              }
              /* other cases shouldn't happen, but return NULL */
              break;
diff -Nrpc base/src/backend/utils/cache/relcache.c sepgsql/src/backend/utils/cache/relcache.c
*** base/src/backend/utils/cache/relcache.c    Fri Jan 23 10:23:37 2009
--- sepgsql/src/backend/utils/cache/relcache.c    Fri Jan 23 10:55:35 2009
***************
*** 55,60 ****
--- 55,61 ----
  #include "optimizer/prep.h"
  #include "optimizer/var.h"
  #include "rewrite/rewriteDefine.h"
+ #include "security/pgace.h"
  #include "storage/fd.h"
  #include "storage/lmgr.h"
  #include "storage/smgr.h"
*************** AllocateRelationDesc(Relation relation,
*** 329,335 ****
      /* initialize relation tuple form */
      relation->rd_rel = relationForm;

!     /* and allocate attribute tuple form storage */
      relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
                                                 relationForm->relhasoids);
      /* which we mark as a reference-counted tupdesc */
--- 330,342 ----
      /* initialize relation tuple form */
      relation->rd_rel = relationForm;

!     /*
!      * and allocate attribute tuple form storage
!      *
!      * Please note that relation->rd_att->tdhasrowacl and tdhasseclabel
!      * have to be fixed up correctly at RelationBuildTupleDesc(), because
!      * security module may need reloptions info to make its decision.
!      */
      relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
                                                 relationForm->relhasoids);
      /* which we mark as a reference-counted tupdesc */
*************** RelationBuildDesc(Oid targetRelId, Relat
*** 887,892 ****
--- 894,905 ----
      /* extract reloptions if any */
      RelationParseRelOptions(relation, pg_class_tuple);

+     /* fixup relation->rd_att->tdhassecacl and tdhasseclabel */
+     relation->rd_att->tdhasrowacl
+         = pgaceTupleDescHasRowAcl(relation, NIL);
+     relation->rd_att->tdhasseclabel
+         = pgaceTupleDescHasSecLabel(relation, NIL);
+
      /*
       * initialize the relation lock manager information
       */
*************** formrdesc(const char *relationName, Oid
*** 1474,1479 ****
--- 1487,1500 ----
      relation->rd_rel->relfilenode = RelationGetRelid(relation);

      /*
+      * Fixup relation->rd_att->tdhasrowacl and tdhasseclabel
+      */
+     RelationGetDescr(relation)->tdhasrowacl
+         = pgaceTupleDescHasRowAcl(relation, NIL);
+     RelationGetDescr(relation)->tdhasseclabel
+         = pgaceTupleDescHasSecLabel(relation, NIL);
+
+     /*
       * initialize the relation lock manager information
       */
      RelationInitLockInfo(relation);        /* see lmgr.c */
*************** BuildHardcodedDescriptor(int natts, Form
*** 2708,2713 ****
--- 2729,2741 ----

      oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

+     /*
+      * NOTE: we assume the returned TupleDesc is only used for
+      * references to toast'ed data, and it is not delivered to
+      * heap_form_tuple(), so TupleDesc->tdhasrowacl and tdhasseclabel
+      * don't give us any effect.
+      * We omit to invoke pgaceTupleDescHasSecurity() here.
+      */
      result = CreateTemplateTupleDesc(natts, hasoids);
      result->tdtypeid = RECORDOID;        /* not right, but we don't care */
      result->tdtypmod = -1;
*************** load_relcache_init_file(void)
*** 3465,3470 ****
--- 3493,3506 ----
              rel->rd_options = NULL;
          }

+         /*
+          * fixup rel->rd_att->tdhassecurity
+          */
+         rel->rd_att->tdhasrowacl
+             = pgaceTupleDescHasRowAcl(rel, NIL);
+         rel->rd_att->tdhasseclabel
+             = pgaceTupleDescHasSecLabel(rel, NIL);
+
          /* mark not-null status */
          if (has_not_null)
          {
diff -Nrpc base/src/backend/utils/cache/syscache.c sepgsql/src/backend/utils/cache/syscache.c
*** base/src/backend/utils/cache/syscache.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/utils/cache/syscache.c    Sat Jan  3 15:58:18 2009
***************
*** 41,46 ****
--- 41,47 ----
  #include "catalog/pg_opfamily.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_rewrite.h"
+ #include "catalog/pg_security.h"
  #include "catalog/pg_statistic.h"
  #include "catalog/pg_ts_config.h"
  #include "catalog/pg_ts_config_map.h"
*************** static const struct cachedesc cacheinfo[
*** 584,589 ****
--- 585,614 ----
          },
          1024
      },
+     {SecurityRelationId,        /*SECURITYOID */
+         SecurityOidIndexId,
+         0,
+         1,
+         {
+             ObjectIdAttributeNumber,
+             0,
+             0,
+             0
+         },
+         128
+     },
+     {SecurityRelationId,        /* SECURITYLABEL */
+         SecuritySeclabelIndexId,
+         0,
+         1,
+         {
+             Anum_pg_security_seclabel,
+             0,
+             0,
+             0
+         },
+         128
+     },
      {StatisticRelationId,        /* STATRELATT */
          StatisticRelidAttnumIndexId,
          Anum_pg_statistic_starelid,
*************** ReleaseSysCache(HeapTuple tuple)
*** 859,864 ****
--- 884,904 ----
  }

  /*
+  * InsertSysCache
+  *      interts a tuple temporary until next CommandCounterIncrement
+  */
+ void InsertSysCache(Oid relid, HeapTuple tuple)
+ {
+     int cacheId;
+
+     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
+     {
+         if (SysCache[cacheId]->cc_reloid == relid)
+             InsertCatCache(SysCache[cacheId], tuple);
+     }
+ }
+
+ /*
   * SearchSysCacheCopy
   *
   * A convenience routine that does SearchSysCache and (if successful)
diff -Nrpc base/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/dfmgr.c
*** base/src/backend/utils/fmgr/dfmgr.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/utils/fmgr/dfmgr.c    Sat Jan  3 15:58:18 2009
***************
*** 23,28 ****
--- 23,29 ----
  #endif
  #include "lib/stringinfo.h"
  #include "miscadmin.h"
+ #include "security/pgace.h"
  #include "utils/dynamic_loader.h"
  #include "utils/hsearch.h"

*************** static void incompatible_module_error(co
*** 76,82 ****
                                      const Pg_magic_struct *module_magic_data);
  static void internal_unload_library(const char *libname);
  static bool file_exists(const char *name);
- static char *expand_dynamic_library_name(const char *name);
  static void check_restricted_library_name(const char *name);
  static char *substitute_libpath_macro(const char *name);
  static char *find_in_dynamic_libpath(const char *basename);
--- 77,82 ----
*************** load_external_function(char *filename, c
*** 109,114 ****
--- 109,117 ----
      /* Expand the possibly-abbreviated filename to an exact path name */
      fullname = expand_dynamic_library_name(filename);

+     /* Check whether the shared library should be loaded, or not */
+     pgaceLoadSharedModule(fullname);
+
      /* Load the shared library, unless we already did */
      lib_handle = internal_load_library(fullname);

*************** load_file(const char *filename, bool res
*** 149,154 ****
--- 152,160 ----
      /* Expand the possibly-abbreviated filename to an exact path name */
      fullname = expand_dynamic_library_name(filename);

+     /* Check whether the library should be loaded, or not */
+     pgaceLoadSharedModule(fullname);
+
      /* Unload the library if currently loaded */
      internal_unload_library(fullname);

*************** file_exists(const char *name)
*** 470,476 ****
   *
   * The result will always be freshly palloc'd.
   */
! static char *
  expand_dynamic_library_name(const char *name)
  {
      bool        have_slash;
--- 476,482 ----
   *
   * The result will always be freshly palloc'd.
   */
! char *
  expand_dynamic_library_name(const char *name)
  {
      bool        have_slash;
diff -Nrpc base/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/init/postinit.c
*** base/src/backend/utils/init/postinit.c    Sat Jan  3 13:01:35 2009
--- sepgsql/src/backend/utils/init/postinit.c    Sat Jan  3 15:58:18 2009
***************
*** 32,37 ****
--- 32,38 ----
  #include "pgstat.h"
  #include "postmaster/autovacuum.h"
  #include "postmaster/postmaster.h"
+ #include "security/pgace.h"
  #include "storage/backendid.h"
  #include "storage/bufmgr.h"
  #include "storage/fd.h"
*************** InitPostgres(const char *in_dbname, Oid
*** 645,650 ****
--- 646,654 ----
      if (!bootstrap)
          pgstat_bestart();

+     /* initialize mandatory access control facilities */
+     pgaceInitialize(bootstrap);
+
      /* close the transaction we started above */
      if (!bootstrap)
          CommitTransactionCommand();
diff -Nrpc base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc.c
*** base/src/backend/utils/misc/guc.c    Thu Jan 22 14:34:54 2009
--- sepgsql/src/backend/utils/misc/guc.c    Thu Jan 22 14:41:23 2009
***************
*** 56,61 ****
--- 56,62 ----
  #include "postmaster/syslogger.h"
  #include "postmaster/walwriter.h"
  #include "regex/regex.h"
+ #include "security/pgace.h"
  #include "storage/bufmgr.h"
  #include "storage/fd.h"
  #include "tcop/tcopprot.h"
*************** static const struct config_enum_entry xm
*** 296,301 ****
--- 297,320 ----
      {NULL, 0, false}
  };

+ static const struct config_enum_entry pgace_feature_options[] = {
+     {"none", PGACE_FEATURE_NONE, false},
+ #ifdef HAVE_SELINUX
+     {"selinux", PGACE_FEATURE_SELINUX, false},
+ #endif
+     {NULL, 0, false}
+ };
+
+ #ifdef HAVE_SELINUX
+ static const struct config_enum_entry sepgsqloption_options[] = {
+     {"default", SEPGSQL_MODE_DEFAULT, false},
+     {"enforcing", SEPGSQL_MODE_ENFORCING, false},
+     {"permissive", SEPGSQL_MODE_PERMISSIVE, false},
+     {"disabled", SEPGSQL_MODE_DISABLED, false},
+     {NULL, 0, false}
+ };
+ #endif
+
  /*
   * Although only "on", "off", and "safe_encoding" are documented, we
   * accept all the likely variants of "on" and "off".
*************** static struct config_bool ConfigureNames
*** 1220,1225 ****
--- 1239,1255 ----
          &IgnoreSystemIndexes,
          false, NULL, NULL
      },
+ #ifdef HAVE_SELINUX
+     {
+         {"sepostgresql_row_level", PGC_POSTMASTER, UNGROUPED,
+          gettext_noop("Availability of row-level security in SE-PostgreSQL."),
+          NULL,
+          GUC_NOT_IN_SAMPLE,
+         },
+         &sepostgresql_row_level,
+         true, NULL, NULL
+     },
+ #endif

      /* End-of-list marker */
      {
*************** static struct config_enum ConfigureNames
*** 2671,2678 ****
          &xmloption,
          XMLOPTION_CONTENT, xmloption_options, NULL, NULL
      },
!
!
      /* End-of-list marker */
      {
          {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL
--- 2701,2725 ----
          &xmloption,
          XMLOPTION_CONTENT, xmloption_options, NULL, NULL
      },
!     {
!         {"pgace_feature", PGC_POSTMASTER, UNGROUPED,
!          gettext_noop("A option to choose an enhanced security feature which is "
!                       "a guest of PGACE security framework"),
!          NULL
!         },
!         &pgace_feature,
!         PGACE_FEATURE_NONE, pgace_feature_options, NULL, NULL
!     },
! #ifdef HAVE_SELINUX
!     {
!         {"sepostgresql", PGC_POSTMASTER, UNGROUPED,
!          gettext_noop("SE-PostgreSQL mode (default|permissive|enforcing|disabled)"),
!          NULL
!         },
!         &sepostgresql_mode,
!         SEPGSQL_MODE_DEFAULT, sepgsqloption_options, NULL, NULL
!     },
! #endif
      /* End-of-list marker */
      {
          {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL
*************** ResetAllOptions(void)
*** 3551,3556 ****
--- 3598,3605 ----
  {
      int            i;

+     pgaceSetDatabaseParam("all", NULL);
+
      for (i = 0; i < num_guc_variables; i++)
      {
          struct config_generic *gconf = guc_variables[i];
*************** ExecSetVariableStmt(VariableSetStmt *stm
*** 5476,5481 ****
--- 5525,5531 ----
      {
          case VAR_SET_VALUE:
          case VAR_SET_CURRENT:
+             pgaceSetDatabaseParam(stmt->name, ExtractSetVariableArgs(stmt));
              set_config_option(stmt->name,
                                ExtractSetVariableArgs(stmt),
                                (superuser() ? PGC_SUSET : PGC_USERSET),
*************** ExecSetVariableStmt(VariableSetStmt *stm
*** 5533,5538 ****
--- 5583,5589 ----
              break;
          case VAR_SET_DEFAULT:
          case VAR_RESET:
+             pgaceSetDatabaseParam(stmt->name, NULL);
              set_config_option(stmt->name,
                                NULL,
                                (superuser() ? PGC_SUSET : PGC_USERSET),
*************** EmitWarningsOnPlaceholders(const char *c
*** 5956,5961 ****
--- 6007,6015 ----
  void
  GetPGVariable(const char *name, DestReceiver *dest)
  {
+     /* Check get param permissions */
+     pgaceGetDatabaseParam(name);
+
      if (guc_name_compare(name, "all") == 0)
          ShowAllGUCConfig(dest);
      else
diff -Nrpc base/src/backend/utils/misc/postgresql.conf.sample sepgsql/src/backend/utils/misc/postgresql.conf.sample
*** base/src/backend/utils/misc/postgresql.conf.sample    Thu Jan 22 14:34:54 2009
--- sepgsql/src/backend/utils/misc/postgresql.conf.sample    Thu Jan 22 14:41:23 2009
***************
*** 485,490 ****
--- 485,496 ----


  #------------------------------------------------------------------------------
+ # ENHANCED SECURITY OPTIONS
+ #------------------------------------------------------------------------------
+
+ #pgace_feature = 'none'
+
+ #------------------------------------------------------------------------------
  # CUSTOMIZED OPTIONS
  #------------------------------------------------------------------------------

diff -Nrpc base/src/include/access/htup.h sepgsql/src/include/access/htup.h
*** base/src/include/access/htup.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/access/htup.h    Sat Jan  3 15:58:18 2009
*************** typedef HeapTupleHeaderData *HeapTupleHe
*** 187,193 ****
   * information stored in t_infomask2:
   */
  #define HEAP_NATTS_MASK            0x07FF    /* 11 bits for number of attributes */
! /* bits 0x3800 are available */
  #define HEAP_HOT_UPDATED        0x4000    /* tuple was HOT-updated */
  #define HEAP_ONLY_TUPLE            0x8000    /* this is heap-only tuple */

--- 187,195 ----
   * information stored in t_infomask2:
   */
  #define HEAP_NATTS_MASK            0x07FF    /* 11 bits for number of attributes */
! /* bits 0x0800 are available */
! #define HEAP_HAS_ROWACL            0x1000    /* tuple has Row-level ACLs */
! #define HEAP_HAS_SECLABEL        0x2000    /* tuple has Security Label */
  #define HEAP_HOT_UPDATED        0x4000    /* tuple was HOT-updated */
  #define HEAP_ONLY_TUPLE            0x8000    /* this is heap-only tuple */

*************** do { \
*** 290,295 ****
--- 292,300 ----
      (tup)->t_choice.t_datum.datum_typmod = (typmod) \
  )

+ #define HeapTupleHeaderHasOid(tup) \
+     ((tup)->t_infomask & HEAP_HASOID)
+
  #define HeapTupleHeaderGetOid(tup) \
  ( \
      ((tup)->t_infomask & HEAP_HASOID) ? \
*************** do { \
*** 349,354 ****
--- 354,400 ----
      (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \
  )

+ #define HeapTupleHeaderHasRowAcl(tup)            \
+     ((tup)->t_infomask2 & HEAP_HAS_ROWACL)
+
+ #define HeapTupleHeaderHasSecLabel(tup)    \
+     ((tup)->t_infomask2 & HEAP_HAS_SECLABEL)
+
+ #define HeapTupleHeaderGetRowAcl(tup)                                    \
+     (                                                                    \
+         HeapTupleHeaderHasRowAcl(tup)                                    \
+         ? (*((Oid *)((char *)(tup) + (tup)->t_hoff                        \
+                      - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0)    \
+                      - (HeapTupleHeaderHasSecLabel(tup) ? sizeof(Oid) : 0) \
+                      - sizeof(Oid))))                                    \
+         : InvalidOid                                                    \
+     )
+
+ #define HeapTupleHeaderGetSecLabel(tup)                                    \
+     (                                                                    \
+         HeapTupleHeaderHasSecLabel(tup)                                    \
+         ? (*(Oid *)((char *)(tup) + (tup)->t_hoff                        \
+                     - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0)    \
+                     - sizeof(Oid)))                                        \
+         : InvalidOid                                                    \
+     )
+
+ #define HeapTupleHeaderSetRowAcl(tup, rowacl)                            \
+     do {                                                                \
+         Assert(HeapTupleHeaderHasRowAcl(tup));                            \
+         *((Oid *)((char *)(tup) + (tup)->t_hoff                            \
+                   - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0)        \
+                   - (HeapTupleHeaderHasSecLabel(tup) ? sizeof(Oid) : 0) \
+                   - sizeof(Oid))) = (rowacl);                            \
+     } while (0)
+
+ #define HeapTupleHeaderSetSecLabel(tup, seclabel)                        \
+     do {                                                                \
+         Assert(HeapTupleHeaderHasSecLabel(tup));                        \
+         *((Oid *)((char *)(tup) + (tup)->t_hoff                            \
+                   - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0)        \
+                   - sizeof(Oid))) = (seclabel);                            \
+     } while(0)

  /*
   * BITMAPLEN(NATTS) -
*************** typedef HeapTupleData *HeapTuple;
*** 543,554 ****
--- 589,620 ----
  #define HeapTupleClearHeapOnly(tuple) \
          HeapTupleHeaderClearHeapOnly((tuple)->t_data)

+ #define HeapTupleHasOid(tuple) \
+         HeapTupleHeaderHasOid((tuple)->t_data)
+
  #define HeapTupleGetOid(tuple) \
          HeapTupleHeaderGetOid((tuple)->t_data)

  #define HeapTupleSetOid(tuple, oid) \
          HeapTupleHeaderSetOid((tuple)->t_data, (oid))

+ #define HeapTupleHasRowAcl(tuple) \
+         HeapTupleHeaderHasRowAcl((tuple)->t_data)
+
+ #define HeapTupleHasSecLabel(tuple) \
+         HeapTupleHeaderHasSecLabel((tuple)->t_data)
+
+ #define HeapTupleGetRowAcl(tuple) \
+         HeapTupleHeaderGetRowAcl((tuple)->t_data)
+
+ #define HeapTupleGetSecLabel(tuple) \
+         HeapTupleHeaderGetSecLabel((tuple)->t_data)
+
+ #define HeapTupleSetRowAcl(tuple, rowacl) \
+         HeapTupleHeaderSetRowAcl((tuple)->t_data, (rowacl))
+
+ #define HeapTupleSetSecLabel(tuple, seclabel) \
+         HeapTupleHeaderSetSecLabel((tuple)->t_data, (seclabel))

  /*
   * WAL record definitions for heapam.c's WAL operations
diff -Nrpc base/src/include/access/sysattr.h sepgsql/src/include/access/sysattr.h
*** base/src/include/access/sysattr.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/access/sysattr.h    Sat Jan  3 15:58:18 2009
***************
*** 25,31 ****
  #define MaxTransactionIdAttributeNumber            (-5)
  #define MaxCommandIdAttributeNumber                (-6)
  #define TableOidAttributeNumber                    (-7)
! #define FirstLowInvalidHeapAttributeNumber        (-8)


  #endif   /* SYSATTR_H */
--- 25,38 ----
  #define MaxTransactionIdAttributeNumber            (-5)
  #define MaxCommandIdAttributeNumber                (-6)
  #define TableOidAttributeNumber                    (-7)
! #define SecurityAclAttributeNumber                (-8)
! #define SecurityLabelAttributeNumber            (-9)
! #define FirstLowInvalidHeapAttributeNumber        (-10)

+ /*
+  * Attribute names for the system-defined attributes
+  */
+ #define SecurityAclAttributeName        "security_acl"
+ #define SecurityLabelAttributeName        "security_label"

  #endif   /* SYSATTR_H */
diff -Nrpc base/src/include/access/tupdesc.h sepgsql/src/include/access/tupdesc.h
*** base/src/include/access/tupdesc.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/access/tupdesc.h    Sat Jan  3 15:58:18 2009
*************** typedef struct tupleDesc
*** 75,80 ****
--- 75,82 ----
      Oid            tdtypeid;        /* composite type ID for tuple type */
      int32        tdtypmod;        /* typmod for tuple type */
      bool        tdhasoid;        /* tuple has oid attribute in its header */
+     bool        tdhasrowacl;    /* tuple has Row-level ACLs in its header */
+     bool        tdhasseclabel;    /* tuple has security label in its header */
      int            tdrefcount;        /* reference count, or -1 if not counting */
  }    *TupleDesc;

diff -Nrpc base/src/include/catalog/heap.h sepgsql/src/include/catalog/heap.h
*** base/src/include/catalog/heap.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/catalog/heap.h    Sat Jan  3 15:58:18 2009
*************** extern Oid heap_create_with_catalog(cons
*** 56,62 ****
                           int oidinhcount,
                           OnCommitAction oncommit,
                           Datum reloptions,
!                          bool allow_system_table_mods);

  extern void heap_drop_with_catalog(Oid relid);

--- 56,63 ----
                           int oidinhcount,
                           OnCommitAction oncommit,
                           Datum reloptions,
!                          bool allow_system_table_mods,
!                          List *pgaceAttrList);

  extern void heap_drop_with_catalog(Oid relid);

*************** extern List *heap_truncate_find_FKs(List
*** 68,79 ****

  extern void InsertPgAttributeTuple(Relation pg_attribute_rel,
                          Form_pg_attribute new_attribute,
!                         CatalogIndexState indstate);

  extern void InsertPgClassTuple(Relation pg_class_desc,
                     Relation new_rel_desc,
                     Oid new_rel_oid,
!                    Datum reloptions);

  extern List *AddRelationNewConstraints(Relation rel,
                            List *newColDefaults,
--- 69,82 ----

  extern void InsertPgAttributeTuple(Relation pg_attribute_rel,
                          Form_pg_attribute new_attribute,
!                         CatalogIndexState indstate,
!                         List *pgaceAttrList);

  extern void InsertPgClassTuple(Relation pg_class_desc,
                     Relation new_rel_desc,
                     Oid new_rel_oid,
!                    Datum reloptions,
!                    List *pgaceAttrList);

  extern List *AddRelationNewConstraints(Relation rel,
                            List *newColDefaults,
*************** extern Form_pg_attribute SystemAttribute
*** 103,108 ****
--- 106,113 ----
  extern Form_pg_attribute SystemAttributeByName(const char *attname,
                        bool relhasoids);

+ extern bool SystemAttributeIsWritable(AttrNumber attnum);
+
  extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind);

  extern void CheckAttributeType(const char *attname, Oid atttypid);
diff -Nrpc base/src/include/catalog/indexing.h sepgsql/src/include/catalog/indexing.h
*** base/src/include/catalog/indexing.h    Fri Jan 23 10:23:37 2009
--- sepgsql/src/include/catalog/indexing.h    Fri Jan 23 10:55:35 2009
*************** DECLARE_UNIQUE_INDEX(pg_type_oid_index,
*** 252,257 ****
--- 252,262 ----
  DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace
oid_ops));
  #define TypeNameNspIndexId    2704

+ DECLARE_UNIQUE_INDEX(pg_security_oid_index, 3401, on pg_security using btree(oid oid_ops));
+ #define SecurityOidIndexId    3401
+ DECLARE_UNIQUE_INDEX(pg_security_seclabel_index, 3402, on pg_security using btree(seclabel text_ops));
+ #define SecuritySeclabelIndexId    3402
+
  DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops));
  #define ForeignDataWrapperOidIndexId    112

diff -Nrpc base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/pg_attribute.h
*** base/src/include/catalog/pg_attribute.h    Fri Jan 23 10:23:37 2009
--- sepgsql/src/include/catalog/pg_attribute.h    Fri Jan 23 11:58:46 2009
*************** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP
*** 130,135 ****
--- 130,141 ----
       */
      char        attalign;

+     /*
+      * attkind is a copy of the relkind field from pg_class for this
+      * attribute. See pg_class.h for more details.
+      */
+     char        attkind;
+
      /* This flag represents the "NOT NULL" constraint */
      bool        attnotnull;

*************** typedef FormData_pg_attribute *Form_pg_a
*** 176,182 ****
   * ----------------
   */

! #define Natts_pg_attribute                18
  #define Anum_pg_attribute_attrelid        1
  #define Anum_pg_attribute_attname        2
  #define Anum_pg_attribute_atttypid        3
--- 182,188 ----
   * ----------------
   */

! #define Natts_pg_attribute                19
  #define Anum_pg_attribute_attrelid        1
  #define Anum_pg_attribute_attname        2
  #define Anum_pg_attribute_atttypid        3
*************** typedef FormData_pg_attribute *Form_pg_a
*** 189,200 ****
  #define Anum_pg_attribute_attbyval        10
  #define Anum_pg_attribute_attstorage    11
  #define Anum_pg_attribute_attalign        12
! #define Anum_pg_attribute_attnotnull    13
! #define Anum_pg_attribute_atthasdef        14
! #define Anum_pg_attribute_attisdropped    15
! #define Anum_pg_attribute_attislocal    16
! #define Anum_pg_attribute_attinhcount    17
! #define Anum_pg_attribute_attacl        18


  /* ----------------
--- 195,207 ----
  #define Anum_pg_attribute_attbyval        10
  #define Anum_pg_attribute_attstorage    11
  #define Anum_pg_attribute_attalign        12
! #define Anum_pg_attribute_attkind        13
! #define Anum_pg_attribute_attnotnull    14
! #define Anum_pg_attribute_atthasdef        15
! #define Anum_pg_attribute_attisdropped    16
! #define Anum_pg_attribute_attislocal    17
! #define Anum_pg_attribute_attinhcount    18
! #define Anum_pg_attribute_attacl        19


  /* ----------------
*************** typedef FormData_pg_attribute *Form_pg_a
*** 212,457 ****
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},       19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typnamespace"},  26, -1,    4,    2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typowner"},       26, -1,    4,    3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typlen"},           21, -1,    2,    4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbyval"},       16, -1,    1,    5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtype"},       18, -1,    1,    6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typcategory"},   18, -1,    1,    7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typispreferred"},16, -1,    1,    8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typisdefined"},  16, -1,    1,    9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdelim"},       18, -1,    1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},       26, -1,    4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},       26, -1,    4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},       26, -1,    4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},       24, -1,    4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},       24, -1,    4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typreceive"},    24, -1,    4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},       24, -1,    4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},       24, -1,    4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},       24, -1,    4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typanalyze"},    24, -1,    4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},       18, -1,    1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1,    1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1,    1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1,    4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},       23, -1,    4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typndims"},       23, -1,    4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
!
! DATA(insert ( 1247 typname            19 -1 NAMEDATALEN    1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace        26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typowner            26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typlen            21 -1 2   4 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1247 typbyval            16 -1 1   5 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typtype            18 -1 1   6 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typcategory        18 -1 1   7 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred    16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined        16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typdelim            18 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typrelid            26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typelem            26 -1 4  12 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typarray            26 -1 4  13 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typinput            24 -1 4  14 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typoutput        24 -1 4  15 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typreceive        24 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typsend            24 -1 4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodin            24 -1 4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodout        24 -1 4  19 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze        24 -1 4  20 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typalign            18 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typstorage        18 -1 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull        16 -1 1  23 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype        26 -1 4  24 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod        23 -1 4  25 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typndims            23 -1 4  26 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin    25 -1 -1 27 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 typdefault        25 -1 -1 28 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 ctid                27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1247 oid                26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmin                28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmin                29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmax                28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmax                29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 tableoid            26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));

  /* ----------------
   *        pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},            19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0
}}, \ 
! { 1255, {"pronamespace"},        26, -1, 4,    2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proowner"},            26, -1, 4,    3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prolang"},            26, -1, 4,    4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"procost"},           700, -1, 4,    5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, {
0} }, \ 
! { 1255, {"prorows"},           700, -1, 4,    6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, {
0} }, \ 
! { 1255, {"provariadic"},        26, -1, 4,    7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisagg"},            16, -1, 1,    8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proiswindow"},        16, -1, 1,    9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prosecdef"},            16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisstrict"},        16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proretset"},            16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provolatile"},        18, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargs"},            21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargdefaults"},    21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorettype"},            26, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proargtypes"},        30, -1, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proallargtypes"},   1028, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargmodes"},      1002, -1, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargnames"},      1009, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargdefaults"},        25, -1, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } },
\
! { 1255, {"prosrc"},                25, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } },
\
! { 1255, {"probin"},                17, -1, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } },
\
! { 1255, {"proconfig"},          1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } },
\
! { 1255, {"proacl"},              1034, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
!
! DATA(insert ( 1255 proname            19 -1 NAMEDATALEN    1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace        26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proowner            26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 prolang            26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 procost           700 -1 4   5 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 prorows           700 -1 4   6 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 provariadic        26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proisagg            16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow        16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef        16 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict        16 -1 1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proretset        16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 provolatile        18 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 pronargs            21 -1 2  14 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults    21 -1 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 prorettype        26 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes        30 -1 -1 17 1 -1 -1 f p i t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 -1 18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes      1002 -1 -1 19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargnames      1009 -1 -1 20 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults    25 -1 -1 21 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 prosrc            25 -1 -1 22 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 probin            17 -1 -1 23 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proconfig      1009 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proacl          1034 -1 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 ctid                27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1255 oid                26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmin                28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmin                29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmax                28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmax                29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 tableoid            26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));

  /* ----------------
   *        pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},      26, -1,    4,    1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attname"},      19, -1, NAMEDATALEN,    2, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 }
},\ 
! { 1249, {"atttypid"},      26, -1,    4,    3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstattarget"}, 23, -1,    4,    4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attlen"},          21, -1,    2,    5, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnum"},          21, -1,    2,    6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attndims"},      23, -1,    4,    7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attcacheoff"},  23, -1,    4,    8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},      23, -1,    4,    9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attbyval"},      16, -1,    1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1,    1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},      18, -1,    1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1,    1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},      16, -1,    1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1,    1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1,    1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1,    4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1,  -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
!
! DATA(insert ( 1249 attrelid            26 -1  4   1 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attname            19 -1 NAMEDATALEN  2 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1249 atttypid            26 -1  4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget    23 -1  4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attlen            21 -1  2   5 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attnum            21 -1  2   6 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attndims            23 -1  4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff        23 -1  4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod        23 -1  4   9 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attbyval            16 -1  1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attstorage        18 -1  1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attalign            18 -1  1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull        16 -1  1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef        16 -1  1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped        16 -1  1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attislocal        16 -1  1  16 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount        23 -1  4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attacl          1034 -1 -1  18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1249 ctid                27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin                28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmin                29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 xmax                28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmax                29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 tableoid            26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));

  /* ----------------
   *        pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},       19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } },
\
! { 1259, {"relnamespace"},  26, -1,    4,    2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltype"},       26, -1,    4,    3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relowner"},       26, -1,    4,    4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relam"},           26, -1,    4,    5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfilenode"},   26, -1,    4,    6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltablespace"}, 26, -1,    4,    7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relpages"},       23, -1,    4,    8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltuples"},       700, -1, 4,    9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0
}}, \ 
! { 1259, {"reltoastrelid"}, 26, -1,    4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1,    4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1,    1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1,    1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},       18, -1,    1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},       21, -1,    2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},       21, -1,    2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasoids"},    16, -1,    1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1,    1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1,    1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1,    1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1,    1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1,    4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},         1034, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1259, {"reloptions"},  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
!
! DATA(insert ( 1259 relname            19 -1 NAMEDATALEN    1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace        26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltype            26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relowner            26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relam            26 -1 4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode        26 -1 4   6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace    26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relpages            23 -1 4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltuples       700 -1 4   9 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid    26 -1 4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid    26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex        16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relisshared        16 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relkind            18 -1 1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relnatts            21 -1 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relchecks        21 -1 2  16 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids        16 -1 1  17 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey        16 -1 1  18 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules        16 -1 1  19 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers    16 -1 1  20 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass    16 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid        28 -1 4  22 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relacl          1034 -1 -1 23 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 reloptions      1009 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 ctid                27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1259 oid                26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmin                28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmin                29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmax                28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmax                29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 tableoid            26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));

  /* ----------------
   *        pg_index
--- 219,477 ----
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},       19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', 'r', true, false, false, true, 0, { 0
}}, \ 
! { 1247, {"typnamespace"},  26, -1,    4,    2, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typowner"},       26, -1,    4,    3, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typlen"},           21, -1,    2,    4, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1247, {"typbyval"},       16, -1,    1,    5, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typtype"},       18, -1,    1,    6, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typcategory"},   18, -1,    1,    7, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typispreferred"},16, -1,    1,    8, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typisdefined"},  16, -1,    1,    9, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typdelim"},       18, -1,    1, 10, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},       26, -1,    4, 11, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},       26, -1,    4, 12, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},       26, -1,    4, 13, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},       24, -1,    4, 14, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},       24, -1,    4, 15, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typreceive"},    24, -1,    4, 16, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},       24, -1,    4, 17, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},       24, -1,    4, 18, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},       24, -1,    4, 19, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typanalyze"},    24, -1,    4, 20, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},       18, -1,    1, 21, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1,    1, 22, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1,    1, 23, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1,    4, 24, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},       23, -1,    4, 25, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1247, {"typndims"},       23, -1,    4, 26, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, -1, 27, 0, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, -1, 28, 0, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 } }
!
! DATA(insert ( 1247 typname            19 -1 NAMEDATALEN    1 0 -1 -1 f p c r t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace        26 -1 4   2 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typowner            26 -1 4   3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typlen            21 -1 2   4 0 -1 -1 t p s r t f f t 0 _null_));
! DATA(insert ( 1247 typbyval            16 -1 1   5 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typtype            18 -1 1   6 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typcategory        18 -1 1   7 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred    16 -1 1   8 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined        16 -1 1   9 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typdelim            18 -1 1  10 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typrelid            26 -1 4  11 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typelem            26 -1 4  12 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typarray            26 -1 4  13 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typinput            24 -1 4  14 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typoutput        24 -1 4  15 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typreceive        24 -1 4  16 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typsend            24 -1 4  17 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typmodin            24 -1 4  18 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typmodout        24 -1 4  19 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze        24 -1 4  20 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typalign            18 -1 1  21 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typstorage        18 -1 1  22 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull        16 -1 1  23 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype        26 -1 4  24 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod        23 -1 4  25 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typndims            23 -1 4  26 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin    25 -1 -1 27 0 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1247 typdefault        25 -1 -1 28 0 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1247 ctid                27 0  6  -1 0 -1 -1 f p s r t f f t 0 _null_));
! DATA(insert ( 1247 oid                26 0  4  -2 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 xmin                28 0  4  -3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 cmin                29 0  4  -4 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 xmax                28 0  4  -5 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 cmax                29 0  4  -6 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 tableoid            26 0  4  -7 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1247 security_acl      1034 0 -1  -8 1 -1 -1 f x i r t f f t 0 _null_));
! DATA(insert ( 1247 security_label    25 0 -1  -9 0 -1 -1 f x i r t f f t 0 _null_));

  /* ----------------
   *        pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},            19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', 'r', true, false, false, true,
0,{ 0 } }, \ 
! { 1255, {"pronamespace"},        26, -1, 4,    2, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proowner"},            26, -1, 4,    3, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"prolang"},            26, -1, 4,    4, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"procost"},           700, -1, 4,    5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', 'r', true, false, false, true,
0,{ 0 } }, \ 
! { 1255, {"prorows"},           700, -1, 4,    6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', 'r', true, false, false, true,
0,{ 0 } }, \ 
! { 1255, {"provariadic"},        26, -1, 4,    7, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proisagg"},            16, -1, 1,    8, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proiswindow"},        16, -1, 1,    9, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"prosecdef"},            16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proisstrict"},        16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } },
\
! { 1255, {"proretset"},            16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"provolatile"},        18, -1, 1, 13, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } },
\
! { 1255, {"pronargs"},            21, -1, 2, 14, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 } },
\
! { 1255, {"pronargdefaults"},    21, -1, 2, 15, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 } },
\
! { 1255, {"prorettype"},            26, -1, 4, 16, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proargtypes"},        30, -1, -1, 17, 1, -1, -1, false, 'p', 'i', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proallargtypes"},   1028, -1, -1, 18, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proargmodes"},      1002, -1, -1, 19, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proargnames"},      1009, -1, -1, 20, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 }
},\ 
! { 1255, {"proargdefaults"},        25, -1, -1, 21, 0, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0
}}, \ 
! { 1255, {"prosrc"},                25, -1, -1, 22, 0, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0
}}, \ 
! { 1255, {"probin"},                17, -1, -1, 23, 0, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0
}}, \ 
! { 1255, {"proconfig"},          1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0
}}, \ 
! { 1255, {"proacl"},              1034, -1, -1, 25, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0
}} 
!
! DATA(insert ( 1255 proname            19 -1 NAMEDATALEN    1 0 -1 -1 f p c r t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace        26 -1 4   2 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 proowner            26 -1 4   3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 prolang            26 -1 4   4 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 procost           700 -1 4   5 0 -1 -1 FLOAT4PASSBYVAL p i r t f f t 0 _null_));
! DATA(insert ( 1255 prorows           700 -1 4   6 0 -1 -1 FLOAT4PASSBYVAL p i r t f f t 0 _null_));
! DATA(insert ( 1255 provariadic        26 -1 4   7 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 proisagg            16 -1 1   8 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow        16 -1 1   9 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef        16 -1 1  10 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict        16 -1 1  11 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1255 proretset        16 -1 1  12 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1255 provolatile        18 -1 1  13 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1255 pronargs            21 -1 2  14 0 -1 -1 t p s r t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults    21 -1 2  15 0 -1 -1 t p s r t f f t 0 _null_));
! DATA(insert ( 1255 prorettype        26 -1 4  16 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes        30 -1 -1 17 1 -1 -1 f p i r t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 -1 18 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes      1002 -1 -1 19 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 proargnames      1009 -1 -1 20 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults    25 -1 -1 21 0 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 prosrc            25 -1 -1 22 0 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 probin            17 -1 -1 23 0 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 proconfig      1009 -1 -1 24 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 proacl          1034 -1 -1 25 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1255 ctid                27 0  6  -1 0 -1 -1 f p s r t f f t 0 _null_));
! DATA(insert ( 1255 oid                26 0  4  -2 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 xmin                28 0  4  -3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 cmin                29 0  4  -4 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 xmax                28 0  4  -5 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 cmax                29 0  4  -6 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 tableoid            26 0  4  -7 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1255 security_acl      1034 0 -1  -8 1 -1 -1 f x i r t f f t 0 _null_));
! DATA(insert ( 1255 security_label    25 0 -1  -9 0 -1 -1 f x i r t f f t 0 _null_));
!

  /* ----------------
   *        pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},      26, -1,    4,    1, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1249, {"attname"},      19, -1, NAMEDATALEN,    2, 0, -1, -1, false, 'p', 'c', 'r', true, false, false, true, 0, {
0} }, \ 
! { 1249, {"atttypid"},      26, -1,    4,    3, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1249, {"attstattarget"}, 23, -1,    4,    4, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1249, {"attlen"},          21, -1,    2,    5, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1249, {"attnum"},          21, -1,    2,    6, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1249, {"attndims"},      23, -1,    4,    7, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1249, {"attcacheoff"},  23, -1,    4,    8, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},      23, -1,    4,    9, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1249, {"attbyval"},      16, -1,    1, 10, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1,    1, 11, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},      18, -1,    1, 12, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attkind"},      18, -1,    1, 13, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1,    1, 14, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},      16, -1,    1, 15, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1,    1, 16, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1,    1, 17, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1,    4, 18, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1,  -1, 19, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 } }
!
! DATA(insert ( 1249 attrelid            26 -1  4   1 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 attname            19 -1 NAMEDATALEN  2 0 -1 -1 f p c r t f f t 0 _null_));
! DATA(insert ( 1249 atttypid            26 -1  4   3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget    23 -1  4   4 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 attlen            21 -1  2   5 0 -1 -1 t p s r t f f t 0 _null_));
! DATA(insert ( 1249 attnum            21 -1  2   6 0 -1 -1 t p s r t f f t 0 _null_));
! DATA(insert ( 1249 attndims            23 -1  4   7 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff        23 -1  4   8 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod        23 -1  4   9 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 attbyval            16 -1  1  10 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 attstorage        18 -1  1  11 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 attalign            18 -1  1  12 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 attkind            18 -1  1  13 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull        16 -1  1  14 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef        16 -1  1  15 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped        16 -1  1  16 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 attislocal        16 -1  1  17 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount        23 -1  4  18 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 attacl          1034 -1 -1  19 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1249 ctid                27 0  6  -1 0 -1 -1 f p s r t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin                28 0  4  -3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 cmin                29 0  4  -4 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 xmax                28 0  4  -5 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 cmax                29 0  4  -6 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 tableoid            26 0  4  -7 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1249 security_acl      1034 0 -1  -8 1 -1 -1 f x i r t f f t 0 _null_));
! DATA(insert ( 1249 security_label    25 0 -1  -9 0 -1 -1 f x i r t f f t 0 _null_));
!

  /* ----------------
   *        pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},       19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', 'r', true, false, false, true, 0, { 0
}}, \ 
! { 1259, {"relnamespace"},  26, -1,    4,    2, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1259, {"reltype"},       26, -1,    4,    3, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1259, {"relowner"},       26, -1,    4,    4, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1259, {"relam"},           26, -1,    4,    5, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 }
},\ 
! { 1259, {"relfilenode"},   26, -1,    4,    6, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1259, {"reltablespace"}, 26, -1,    4,    7, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1259, {"relpages"},       23, -1,    4,    8, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 1259, {"reltuples"},       700, -1, 4,    9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', 'r', true, false, false, true,
0,{ 0 } }, \ 
! { 1259, {"reltoastrelid"}, 26, -1,    4, 10, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1,    4, 11, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1,    1, 12, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1,    1, 13, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},       18, -1,    1, 14, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},       21, -1,    2, 15, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},       21, -1,    2, 16, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 } },
\
! { 1259, {"relhasoids"},    16, -1,    1, 17, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1,    1, 18, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1,    1, 19, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1,    1, 20, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1,    1, 21, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1,    4, 22, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},         1034, -1, -1, 23, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 } },
\
! { 1259, {"reloptions"},  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 } }
!
! DATA(insert ( 1259 relname            19 -1 NAMEDATALEN    1 0 -1 -1 f p c r t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace        26 -1 4   2 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 reltype            26 -1 4   3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 relowner            26 -1 4   4 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 relam            26 -1 4   5 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode        26 -1 4   6 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace    26 -1 4   7 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 relpages            23 -1 4   8 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 reltuples       700 -1 4   9 0 -1 -1 FLOAT4PASSBYVAL p i r t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid    26 -1 4  10 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid    26 -1 4  11 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex        16 -1 1  12 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relisshared        16 -1 1  13 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relkind            18 -1 1  14 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relnatts            21 -1 2  15 0 -1 -1 t p s r t f f t 0 _null_));
! DATA(insert ( 1259 relchecks        21 -1 2  16 0 -1 -1 t p s r t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids        16 -1 1  17 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey        16 -1 1  18 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules        16 -1 1  19 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers    16 -1 1  20 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass    16 -1 1  21 0 -1 -1 t p c r t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid        28 -1 4  22 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 relacl          1034 -1 -1 23 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1259 reloptions      1009 -1 -1 24 1 -1 -1 f x i r f f f t 0 _null_));
! DATA(insert ( 1259 ctid                27 0  6  -1 0 -1 -1 f p s r t f f t 0 _null_));
! DATA(insert ( 1259 oid                26 0  4  -2 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 xmin                28 0  4  -3 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 cmin                29 0  4  -4 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 xmax                28 0  4  -5 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 cmax                29 0  4  -6 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 tableoid            26 0  4  -7 0 -1 -1 t p i r t f f t 0 _null_));
! DATA(insert ( 1259 security_acl      1034 0 -1  -8 1 -1 -1 f x i r t f f t 0 _null_));
! DATA(insert ( 1259 security_label    25 0 -1  -9 0 -1 -1 f x i r t f f t 0 _null_));
!

  /* ----------------
   *        pg_index
*************** DATA(insert ( 1259 tableoid            26 0  4  -
*** 462,480 ****
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},        26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},            26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},            21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},        16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},        16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},    16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},        16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},        16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},        16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},            22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},            30, -1, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indoption"},            22, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indexprs"},            25, -1, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 0, {"indpred"},            25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }

  #endif   /* PG_ATTRIBUTE_H */
--- 482,500 ----
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},        26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},            26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},            21, -1, 2, 3, 0, -1, -1, true, 'p', 's', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},        16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},        16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},    16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},        16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},        16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},        16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},            22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', 'r', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},            30, -1, -1, 11, 1, -1, -1, false, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 0, {"indoption"},            22, -1, -1, 12, 1, -1, -1, false, 'p', 'i', 'r', true, false, false, true, 0, { 0 } },
\
! { 0, {"indexprs"},            25, -1, -1, 13, 0, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 } },
\
! { 0, {"indpred"},            25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', 'r', false, false, false, true, 0, { 0 } }

  #endif   /* PG_ATTRIBUTE_H */
diff -Nrpc base/src/include/catalog/pg_class.h sepgsql/src/include/catalog/pg_class.h
*** base/src/include/catalog/pg_class.h    Fri Jan 23 10:23:37 2009
--- sepgsql/src/include/catalog/pg_class.h    Fri Jan 23 11:58:46 2009
*************** typedef FormData_pg_class *Form_pg_class
*** 123,129 ****
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type        PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute    PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 18 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc        PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
--- 123,129 ----
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type        PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute    PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 19 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc        PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
diff -Nrpc base/src/include/catalog/pg_proc.h sepgsql/src/include/catalog/pg_proc.h
*** base/src/include/catalog/pg_proc.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/catalog/pg_proc.h    Mon Jan  5 17:23:27 2009
*************** DESCR("I/O");
*** 4300,4305 ****
--- 4300,4326 ----
  DATA(insert OID = 2963 (  uuid_hash           PGNSP PGUID 12 1 0 0 f f f t f i 1 0 23 "2950" _null_ _null_ _null_
_null_uuid_hash _null_ _null_ _null_ )); 
  DESCR("hash");

+ /* PostgreSQL Access Control Extension related functions */
+ DATA(insert OID = 3410 ( lo_get_security        PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "26"    _null_ _null_ _null_
_null_lo_get_security _null_ _null_ _null_ )); 
+ DATA(insert OID = 3411 ( lo_set_security        PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "26 25" _null_ _null_ _null_
_null_lo_set_security _null_ _null_ _null_ )); 
+
+ /* Row-level Database ACLs related function */
+ DATA(insert OID = 3430 ( rowacl_grant            PGNSP PGUID 12 1 0 0 f f f t f v 4 0 1034 "26 1034 25 25" _null_
_null__null_ _null_ rowacl_grant _null_ _null_ _null_)); 
+ DATA(insert OID = 3431 ( rowacl_revoke            PGNSP PGUID 12 1 0 0 f f f t f v 4 0 1034 "26 1034 25 25" _null_
_null__null_ _null_ rowacl_revoke _null_ _null_ _null_)); 
+ DATA(insert OID = 3432 ( rowacl_revoke_cascade        PGNSP PGUID 12 1 0 0 f f f t f v 4 0 1034 "26 1034 25 25"
_null__null_ _null_ _null_ rowacl_revoke_cascade _null_ _null_ _null_)); 
+
+ /* SE-PostgreSQL related function */
+ DATA(insert OID = 3450 ( sepgsql_getcon            PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_
_null_sepgsql_getcon _null_ _null_ _null_ )); 
+ DATA(insert OID = 3451 ( sepgsql_getservcon        PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_
_null_sepgsql_getservcon _null_ _null_ _null_ )); 
+ DATA(insert OID = 3452 ( sepgsql_get_user        PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_
_null_sepgsql_get_user _null_ _null_ _null_ )); 
+ DATA(insert OID = 3453 ( sepgsql_set_user        PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_
_null_sepgsql_set_user _null_ _null_ _null_ )); 
+ DATA(insert OID = 3454 ( sepgsql_get_role        PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_
_null_sepgsql_get_role _null_ _null_ _null_ )); 
+ DATA(insert OID = 3455 ( sepgsql_set_role        PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_
_null_sepgsql_set_role _null_ _null_ _null_ )); 
+ DATA(insert OID = 3456 ( sepgsql_get_type        PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_
_null_sepgsql_get_type _null_ _null_ _null_ )); 
+ DATA(insert OID = 3457 ( sepgsql_set_type        PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_ _null_
_null_sepgsql_set_type _null_ _null_ _null_ )); 
+ DATA(insert OID = 3458 ( sepgsql_get_range        PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "25" _null_ _null_ _null_
_null_sepgsql_get_range _null_ _null_ _null_ )); 
+ DATA(insert OID = 3459 ( sepgsql_set_range        PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 25" _null_ _null_
_null__null_ sepgsql_set_range _null_ _null_ _null_ )); 
+
  /* enum related procs */
  DATA(insert OID = 3504 (  anyenum_in    PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3500 "2275" _null_ _null_ _null_ _null_
anyenum_in_null_ _null_ _null_ )); 
  DESCR("I/O");
diff -Nrpc base/src/include/catalog/pg_proc_fn.h sepgsql/src/include/catalog/pg_proc_fn.h
*** base/src/include/catalog/pg_proc_fn.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/catalog/pg_proc_fn.h    Sat Jan  3 15:58:18 2009
*************** extern Oid ProcedureCreate(const char *p
*** 37,43 ****
                  List *parameterDefaults,
                  Datum proconfig,
                  float4 procost,
!                 float4 prorows);

  extern bool function_parse_error_transpose(const char *prosrc);

--- 37,44 ----
                  List *parameterDefaults,
                  Datum proconfig,
                  float4 procost,
!                 float4 prorows,
!                 void *pgaceItem);

  extern bool function_parse_error_transpose(const char *prosrc);

diff -Nrpc base/src/include/catalog/pg_security.h sepgsql/src/include/catalog/pg_security.h
*** base/src/include/catalog/pg_security.h    Thu Jan  1 09:00:00 1970
--- sepgsql/src/include/catalog/pg_security.h    Fri Sep 21 01:08:03 2007
***************
*** 0 ****
--- 1,31 ----
+ /*
+  * src/include/catalog/pg_security.h
+  *    Definition of the security label relation (pg_security)
+  *
+  * Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+  */
+ #ifndef PG_SECURITY_H
+ #define PG_SECURITY_H
+
+ #define SecurityRelationId        3400
+
+ CATALOG(pg_security,3400) BKI_SHARED_RELATION
+ {
+     text        seclabel;        /* text representation of security label */
+ } FormData_pg_security;
+
+ /* ----------------
+  *     Form_pg_security corresponds to a pointer to a tuple with
+  *     the format of pg_security relation.
+  * ----------------
+  */
+ typedef FormData_pg_security *Form_pg_security;
+
+ /* ----------------
+  *        compiler constants for pg_selinux
+  * ----------------
+  */
+ #define Natts_pg_security                1
+ #define Anum_pg_security_seclabel        1
+
+ #endif   /* PG_SELINUX_H */
diff -Nrpc base/src/include/catalog/pg_type.h sepgsql/src/include/catalog/pg_type.h
*** base/src/include/catalog/pg_type.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/catalog/pg_type.h    Sat Jan  3 15:58:18 2009
*************** DATA(insert OID = 1033 (  aclitem     PGNSP
*** 459,464 ****
--- 459,465 ----
  DESCR("access control list");
  #define ACLITEMOID        1033
  DATA(insert OID = 1034 (  _aclitem     PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv
array_send- - - i x f 0 -1 0 _null_ _null_ )); 
+ #define ACLITEMARRAYOID    1034
  DATA(insert OID = 1040 (  _macaddr     PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv
array_send- - - i x f 0 -1 0 _null_ _null_ )); 
  DATA(insert OID = 1041 (  _inet         PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv
array_send- - - i x f 0 -1 0 _null_ _null_ )); 
  DATA(insert OID = 651  (  _cidr         PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv
array_send- - - i x f 0 -1 0 _null_ _null_ )); 
diff -Nrpc base/src/include/executor/executor.h sepgsql/src/include/executor/executor.h
*** base/src/include/executor/executor.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/executor/executor.h    Sat Jan  3 15:58:18 2009
*************** extern TupleHashEntry FindTupleHashEntry
*** 130,137 ****
  /*
   * prototypes from functions in execJunk.c
   */
! extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid,
!                    TupleTableSlot *slot);
  extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
                               TupleDesc cleanTupType,
                               TupleTableSlot *slot);
--- 130,138 ----
  /*
   * prototypes from functions in execJunk.c
   */
! extern JunkFilter *ExecInitJunkFilter(List *targetList,
!                                       bool hasoid, bool hassecacl, bool hasseclabel,
!                                       TupleTableSlot *slot);
  extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
                               TupleDesc cleanTupType,
                               TupleTableSlot *slot);
*************** extern void InitResultRelInfo(ResultRelI
*** 163,168 ****
--- 164,171 ----
                    bool doInstrument);
  extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
  extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
+ extern bool ExecContextForcesRowAcl(PlanState *planstate, bool *hasrowacl);
+ extern bool ExecContextForcesSecLabel(PlanState *planstate, bool *hasseclabel);
  extern void ExecConstraints(ResultRelInfo *resultRelInfo,
                  TupleTableSlot *slot, EState *estate);
  extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
*************** extern void ExecInitScanTupleSlot(EState
*** 216,223 ****
  extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
  extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
                        TupleDesc tupType);
! extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
! extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
  extern TupleDesc ExecTypeFromExprList(List *exprList);
  extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);

--- 219,226 ----
  extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
  extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
                        TupleDesc tupType);
! extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid, bool hassecacl, bool hasseclabel);
! extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hassecacl, bool hasseclabel);
  extern TupleDesc ExecTypeFromExprList(List *exprList);
  extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);

diff -Nrpc base/src/include/executor/tuptable.h sepgsql/src/include/executor/tuptable.h
*** base/src/include/executor/tuptable.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/executor/tuptable.h    Sat Jan  3 15:58:18 2009
*************** typedef struct TupleTableSlot
*** 118,123 ****
--- 118,127 ----
      MinimalTuple tts_mintuple;    /* set if it's a minimal tuple, else NULL */
      HeapTupleData tts_minhdr;    /* workspace if it's a minimal tuple */
      long        tts_off;        /* saved state for slot_deform_tuple */
+
+     /* temporary storage variables for writable system column */
+     Datum        tts_rowacl;        /* for row level acls */
+     Datum        tts_seclabel;    /* for security label */
  } TupleTableSlot;

  /*
diff -Nrpc base/src/include/fmgr.h sepgsql/src/include/fmgr.h
*** base/src/include/fmgr.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/fmgr.h    Fri Jan 16 17:05:27 2009
*************** typedef struct FmgrInfo
*** 53,58 ****
--- 53,60 ----
      void       *fn_extra;        /* extra space for use by handler */
      MemoryContext fn_mcxt;        /* memory context to store fn_extra in */
      fmNodePtr    fn_expr;        /* expression parse tree for call, or NULL */
+
+     void       *fn_pgaceItem;    /* PGACE opaque field */
  } FmgrInfo;

  /*
*************** extern bool get_call_expr_arg_stable(fmN
*** 524,529 ****
--- 526,532 ----
   */
  extern char *Dynamic_library_path;

+ extern char *expand_dynamic_library_name(const char *name);
  extern PGFunction load_external_function(char *filename, char *funcname,
                         bool signalNotFound, void **filehandle);
  extern PGFunction lookup_external_function(void *filehandle, char *funcname);
diff -Nrpc base/src/include/libpq/be-fsstubs.h sepgsql/src/include/libpq/be-fsstubs.h
*** base/src/include/libpq/be-fsstubs.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/libpq/be-fsstubs.h    Sat Jan  3 15:58:18 2009
*************** extern Datum lo_tell(PG_FUNCTION_ARGS);
*** 37,42 ****
--- 37,45 ----
  extern Datum lo_unlink(PG_FUNCTION_ARGS);
  extern Datum lo_truncate(PG_FUNCTION_ARGS);

+ extern Datum lo_get_security(PG_FUNCTION_ARGS);
+ extern Datum lo_set_security(PG_FUNCTION_ARGS);
+
  /*
   * These are not fmgr-callable, but are available to C code.
   * Probably these should have had the underscore-free names,
diff -Nrpc base/src/include/nodes/nodes.h sepgsql/src/include/nodes/nodes.h
*** base/src/include/nodes/nodes.h    Fri Jan 23 10:23:37 2009
--- sepgsql/src/include/nodes/nodes.h    Fri Jan 23 10:55:35 2009
*************** typedef enum NodeTag
*** 390,396 ****
      T_TriggerData = 950,        /* in commands/trigger.h */
      T_ReturnSetInfo,            /* in nodes/execnodes.h */
      T_WindowObjectData,            /* private in nodeWindowAgg.c */
!     T_TIDBitmap                    /* in nodes/tidbitmap.h */
  } NodeTag;

  /*
--- 390,397 ----
      T_TriggerData = 950,        /* in commands/trigger.h */
      T_ReturnSetInfo,            /* in nodes/execnodes.h */
      T_WindowObjectData,            /* private in nodeWindowAgg.c */
!     T_TIDBitmap,                    /* in nodes/tidbitmap.h */
!     T_SelinuxEvalItem,            /* in nodes/security.h */
  } NodeTag;

  /*
diff -Nrpc base/src/include/nodes/parsenodes.h sepgsql/src/include/nodes/parsenodes.h
*** base/src/include/nodes/parsenodes.h    Fri Jan 23 10:23:37 2009
--- sepgsql/src/include/nodes/parsenodes.h    Fri Jan 23 10:55:35 2009
*************** typedef struct Query
*** 152,157 ****
--- 152,158 ----

      Node       *setOperations;    /* set-operation tree if this is top level of
                                   * a UNION/INTERSECT/EXCEPT query */
+     Node       *pgaceItem;        /* PGACE: an opaque item for security purpose */
  } Query;


*************** typedef struct ColumnDef
*** 471,476 ****
--- 472,478 ----
      Node       *raw_default;    /* default value (untransformed parse tree) */
      char       *cooked_default; /* nodeToString representation */
      List       *constraints;    /* other constraints on column */
+     Node       *pgaceItem;        /* PGACE: security attribute */
  } ColumnDef;

  /*
*************** typedef struct RangeTblEntry
*** 717,722 ****
--- 719,735 ----
      Oid            checkAsUser;    /* if valid, check access as this role */
      Bitmapset  *selectedCols;    /* columns needing SELECT permission */
      Bitmapset  *modifiedCols;    /* columns needing INSERT/UPDATE permission */
+
+     /*
+      * PGACE allows its guest to use pgaceTuplePerms to mark required
+      * permission set for tuple-level access controls. This field is
+      * copied to Scan node (like SeqScan), and it can be refered within
+      * pgaceExecScan() hook.
+      * Please note that the wired rowacl reserves the least 8-bits
+      * (0x000000ff), so any other optional feature should not use
+      * these bits.
+      */
+     uint32        pgaceTuplePerms;
  } RangeTblEntry;

  /*
*************** typedef enum AlterTableType
*** 1133,1139 ****
      AT_EnableReplicaRule,        /* ENABLE REPLICA RULE name */
      AT_DisableRule,                /* DISABLE RULE name */
      AT_AddInherit,                /* INHERIT parent */
!     AT_DropInherit                /* NO INHERIT parent */
  } AlterTableType;

  typedef struct AlterTableCmd    /* one subcommand of an ALTER TABLE */
--- 1146,1153 ----
      AT_EnableReplicaRule,        /* ENABLE REPLICA RULE name */
      AT_DisableRule,                /* DISABLE RULE name */
      AT_AddInherit,                /* INHERIT parent */
!     AT_DropInherit,                /* NO INHERIT parent */
!     AT_SetSecurityLabel,        /* PGACE: set security label */
  } AlterTableType;

  typedef struct AlterTableCmd    /* one subcommand of an ALTER TABLE */
*************** typedef struct CreateStmt
*** 1336,1341 ****
--- 1350,1356 ----
      List       *options;        /* options from WITH clause */
      OnCommitAction oncommit;    /* what do we do at COMMIT? */
      char       *tablespacename; /* table space to use, or NULL */
+     Node       *pgaceItem;        /* PGACE: security attribute */
  } CreateStmt;

  /* ----------
diff -Nrpc base/src/include/nodes/plannodes.h sepgsql/src/include/nodes/plannodes.h
*** base/src/include/nodes/plannodes.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/nodes/plannodes.h    Sat Jan  3 15:58:18 2009
*************** typedef struct PlannedStmt
*** 76,81 ****
--- 76,83 ----
      List       *invalItems;        /* other dependencies, as PlanInvalItems */

      int            nParamExec;        /* number of PARAM_EXEC Params used */
+
+     Node       *pgaceItem;        /* PGACE: an opaque item for security purpose */
  } PlannedStmt;

  /* macro for fetching the Plan associated with a SubPlan node */
*************** typedef struct Scan
*** 239,244 ****
--- 241,254 ----
  {
      Plan        plan;
      Index        scanrelid;        /* relid is index into the range table */
+
+     /*
+      * pgaceTuplePerms is used to show permission set to be applied to
+      * tuple-leve access controls by security module.
+      * It is copied from related RangeTblEntry's one when Scan structure
+      * is created.
+      */
+     uint32        pgaceTuplePerms;
  } Scan;

  /* ----------------
diff -Nrpc base/src/include/nodes/relation.h sepgsql/src/include/nodes/relation.h
*** base/src/include/nodes/relation.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/nodes/relation.h    Sat Jan  3 15:58:18 2009
*************** typedef struct RelOptInfo
*** 383,388 ****
--- 383,390 ----
       * list just to avoid recomputing the best inner indexscan repeatedly for
       * similar outer relations.  See comments for InnerIndexscanInfo.
       */
+
+     uint32        pgaceTuplePerms;        /* copied from RangeTblEntry */
  } RelOptInfo;

  /*
diff -Nrpc base/src/include/nodes/security.h sepgsql/src/include/nodes/security.h
*** base/src/include/nodes/security.h    Thu Jan  1 09:00:00 1970
--- sepgsql/src/include/nodes/security.h    Wed Jan 21 16:59:48 2009
***************
*** 0 ****
--- 1,40 ----
+ /*-------------------------------------------------------------------------
+  *
+  * src/include/nodes/security.h
+  *    definitions for security extention related nodes
+  *
+  * Portions Copyright (c) 2007-2008, PostgreSQL Global Development Group
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef NODES_SECURITY_H
+ #define NODES_SECURITY_H
+
+ #include "access/attnum.h"
+ #include "nodes/nodes.h"
+
+ /*
+  * SelinuxEvalItem
+  *
+  * Required permissions on tables/columns used by SE-PostgreSQL.
+  * It is constracted just after query rewriter phase, then its
+  * list is checked based on the security policy of operating
+  * system.
+  *
+  * NOTE: attperms array can contains system attributes and
+  * whole-row-reference, so it is indexed as
+  *   attperms[(attnum) + FirstLowInvalidHeapAttributeNumber - 1]
+  */
+ typedef struct SelinuxEvalItem
+ {
+     NodeTag        type;
+
+     Oid            relid;        /* relation id */
+     bool        inh;        /* flags to inheritable/only */
+
+     uint32        relperms;    /* required permissions on table */
+     uint32        nattrs;        /* length of attperms */
+     uint32       *attperms;    /* required permissions on columns */
+ } SelinuxEvalItem;
+
+ #endif    /* NODES_SECURITY_H */
diff -Nrpc base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in
*** base/src/include/pg_config.h.in    Tue Jan 13 09:22:28 2009
--- sepgsql/src/include/pg_config.h.in    Tue Jan 13 09:39:35 2009
***************
*** 388,393 ****
--- 388,396 ----
  /* Define to 1 if you have the <security/pam_appl.h> header file. */
  #undef HAVE_SECURITY_PAM_APPL_H

+ /* Define to 1 if you enable SELinux support */
+ #undef HAVE_SELINUX
+
  /* Define to 1 if you have the `setproctitle' function. */
  #undef HAVE_SETPROCTITLE

diff -Nrpc base/src/include/security/pgace.h sepgsql/src/include/security/pgace.h
*** base/src/include/security/pgace.h    Thu Jan  1 09:00:00 1970
--- sepgsql/src/include/security/pgace.h    Wed Jan 21 17:22:37 2009
***************
*** 0 ****
--- 1,181 ----
+ /*
+  * include/security/pgace.h
+  *    headers for PostgreSQL Access Control Extension (PGACE)
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  */
+ #ifndef PGACE_H
+ #define PGACE_H
+
+ #include "access/htup.h"
+ #include "commands/trigger.h"
+ #include "executor/execdesc.h"
+ #include "fmgr.h"
+ #include "nodes/params.h"
+ #include "nodes/parsenodes.h"
+ #include "nodes/plannodes.h"
+ #include "storage/large_object.h"
+ #include "utils/rel.h"
+
+ #include "security/rowacl.h"
+ #ifdef HAVE_SELINUX
+ #include "security/sepgsql.h"
+ #endif
+
+ /*
+  * pgace_feature : GUC parameter to choose an enhanced security feature
+  */
+ typedef enum
+ {
+     PGACE_FEATURE_NONE,
+ #ifdef HAVE_SELINUX
+     PGACE_FEATURE_SELINUX,
+ #endif
+ } PgaceFeatureOpts;
+
+ extern int pgace_feature;
+
+ /*
+  * Initialization hooks
+  */
+ extern Size pgaceShmemSize(void);
+ extern void pgaceInitialize(bool is_bootstrap);
+ extern pid_t pgaceStartupWorkerProcess(void);
+
+ /*
+  * SQL proxy hooks
+  */
+ extern List *pgacePostQueryRewrite(List *queryList);
+ extern void pgaceExecutorStart(QueryDesc *queryDesc, int eflags);
+ extern void pgaceProcessUtility(Node *parsetree, ParamListInfo params,
+                                 bool isTopLevel);
+ /*
+  * HeapTuple input/output hooks
+  */
+ extern bool pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot);
+ extern bool pgaceHeapTupleInsert(Relation rel, HeapTuple tuple,
+                                  bool is_internal, bool with_returning);
+ extern bool pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
+                                  bool is_internal, bool with_returning);
+ extern bool pgaceHeapTupleDelete(Relation rel, ItemPointer otid,
+                                  bool is_internal, bool with_returning);
+ /*
+  * Enhanced SQL statements
+  */
+ extern bool pgaceIsGramSecurityItem(DefElem *defel);
+ extern void pgaceGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel);
+ extern void pgaceGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel);
+ extern void pgaceGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel);
+ extern void pgaceGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel);
+ extern void pgaceGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel);
+ extern void pgaceGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel);
+ extern void pgaceGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel);
+ extern void pgaceGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel);
+
+ /*
+  * Function related hooks
+  */
+ extern void pgaceCallFunction(FmgrInfo *finfo);
+ extern void pgaceCallAggFunction(HeapTuple aggTuple);
+ extern bool pgaceCallTriggerFunction(TriggerData *tgdata);
+ extern void pgaceBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid,
+                                      Datum *rowacl_private, Datum *pgace_private);
+ extern void pgaceEndPerformCheckFK(Relation rel,
+                                    Datum rowacl_private, Datum pgace_private);
+ extern bool pgaceAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple);
+
+ /*
+  * Misc hooks
+  */
+ extern void pgaceSetDatabaseParam(const char *name, char *argstring);
+ extern void pgaceGetDatabaseParam(const char *name);
+ extern void pgaceExecTruncate(List *trunc_rels);
+ extern void pgaceLockTable(Oid relid);
+
+ /*
+  * COPY TO/FROM statement hooks
+  */
+ extern void pgaceCopyTable(Relation rel, List *attNumList, bool isFrom);
+ extern void pgaceCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom);
+ extern bool pgaceCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple);
+
+ /*
+  * Loadable shared library module hooks
+  */
+ extern void pgaceLoadSharedModule(const char *filename);
+
+ /*
+  * Binary Large Object hooks
+  */
+ extern void pgaceLargeObjectCreate(Relation rel, HeapTuple tuple);
+ extern void pgaceLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem);
+ extern void pgaceLargeObjectRead(LargeObjectDesc *lodesc, int length);
+ extern void pgaceLargeObjectWrite(LargeObjectDesc *lodesc, int length);
+ extern void pgaceLargeObjectTruncate(LargeObjectDesc *lodesc, int offset);
+ extern void pgaceLargeObjectImport(Oid loid, int fdesc, const char *filename);
+ extern void pgaceLargeObjectExport(Oid loid, int fdesc, const char *filename);
+ extern void pgaceLargeObjectGetSecurity(Relation rel, HeapTuple tuple);
+ extern void pgaceLargeObjectSetSecurity(Relation rel,
+                                         HeapTuple newtup, HeapTuple oldtup);
+ /*
+  * Security Label hooks
+  */
+ extern bool pgaceTupleDescHasRowAcl(Relation rel, List *relopts);
+ extern bool pgaceTupleDescHasSecLabel(Relation rel, List *relopts);
+ extern char *pgaceTranslateSecurityLabelIn(char *seclabel);
+ extern char *pgaceTranslateSecurityLabelOut(char *seclabel);
+ extern bool pgaceCheckValidSecurityLabel(char *seclabel);
+ extern char *pgaceUnlabeledSecurityLabel(void);
+ extern char *pgaceSecurityLabelOfLabel(void);
+
+ /*
+  * PGACE common facilities (not hooks)
+  */
+
+ /* security label management */
+ extern void pgacePostBootstrapingMode(void);
+
+ extern Oid pgaceLookupSecurityId(char *label);
+
+ extern char *pgaceLookupSecurityLabel(Oid sid);
+
+ extern Oid pgaceSecurityLabelToSid(char *label);
+
+ extern char *pgaceSidToSecurityLabel(Oid sid);
+
+ /* Enhanced SQL statements related */
+ extern List *pgaceRelationAttrList(CreateStmt *stmt);
+
+ extern void pgaceCreateRelationCommon(Relation rel, HeapTuple tuple,
+                                       List *pgaceAttrList);
+ extern void pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple,
+                                        List *pgaceAttrList);
+ extern void pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd);
+
+ /* Export security system columns */
+ extern Datum pgaceHeapGetSecurityLabelSysattr(HeapTuple tuple);
+
+ /*
+  * SQL functions
+  */
+
+ /* SE-PostgreSQL */
+ extern Datum sepgsql_getcon(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_getservcon(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_get_user(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_get_role(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_get_type(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_get_range(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_set_user(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_set_role(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_set_type(PG_FUNCTION_ARGS);
+ extern Datum sepgsql_set_range(PG_FUNCTION_ARGS);
+
+ /* Row-level ACLs */
+ extern Datum rowacl_grant(PG_FUNCTION_ARGS);
+ extern Datum rowacl_revoke(PG_FUNCTION_ARGS);
+ extern Datum rowacl_revoke_cascade(PG_FUNCTION_ARGS);
+
+ #endif // PGACE_H
diff -Nrpc base/src/include/security/rowacl.h sepgsql/src/include/security/rowacl.h
*** base/src/include/security/rowacl.h    Thu Jan  1 09:00:00 1970
--- sepgsql/src/include/security/rowacl.h    Fri Jan 16 10:31:05 2009
***************
*** 0 ****
--- 1,41 ----
+ /*
+  * src/include/security/rowacl.h
+  *   headers for Row-level database ACL support
+  */
+ #ifndef ROWACL_H
+ #define ROWACL_H
+
+ #include "utils/acl.h"
+
+ extern void rowaclInitialize(bool is_bootstrap);
+
+ extern List *rowaclPostQueryRewrite(List *queryList);
+
+ extern Datum rowaclBeginPerformCheckFK(Relation rel, bool is_primary, Oid userid_saved);
+
+ extern void rowaclEndPerformCheckFK(Relation rel, Datum rowacl_private);
+
+ extern bool rowaclExecScan(Scan *scan, Relation rel, TupleTableSlot *slot);
+
+ extern bool rowaclCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple);
+
+ extern bool rowaclHeapTupleInsert(Relation rel, HeapTuple tuple,
+                                   bool is_internal, bool with_returning);
+
+ extern bool rowaclHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
+                                   bool is_internal, bool with_returning);
+
+ extern bool rowaclHeapTupleDelete(Relation rel, ItemPointer otid,
+                                   bool is_internal, bool with_returning);
+
+ extern bool rowaclTupleDescHasRowAcl(Relation rel, List *relopts);
+
+ extern Acl *rowaclSidToSecurityAcl(Oid sid, Oid ownerId);
+
+ extern Oid rowaclSecurityAclToSid(Acl *acl);
+
+ extern Datum rowaclHeapGetSecurityAclSysattr(HeapTuple tuple);
+
+ extern void rawaclValidateDefaultRowAclRelopt(const char *value);
+
+ #endif  /* ROWACL_H */
diff -Nrpc base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h
*** base/src/include/security/sepgsql.h    Thu Jan  1 09:00:00 1970
--- sepgsql/src/include/security/sepgsql.h    Wed Jan 21 17:22:37 2009
***************
*** 0 ****
--- 1,241 ----
+ /*
+  * src/include/security/sepgsql.h
+  *    headers for Security-Enhanced PostgreSQL (SE-PostgreSQL)
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  */
+ #ifndef SEPGSQL_H
+ #define SEPGSQL_H
+
+ #include <selinux/selinux.h>
+ #include <selinux/flask.h>
+ #include <selinux/av_permissions.h>
+
+ /*
+  * SE-PostgreSQL modes
+  */
+ typedef enum
+ {
+     SEPGSQL_MODE_DEFAULT,
+     SEPGSQL_MODE_ENFORCING,
+     SEPGSQL_MODE_PERMISSIVE,
+     SEPGSQL_MODE_DISABLED,
+ } SepgsqlModeType;
+
+ extern int sepostgresql_mode;
+ extern bool sepostgresql_row_level;
+
+ /*
+  * Permission bits delivered to sepgsqlCheckTuplePerms().
+  * Please note that 0x000000ff of RangeTblEntry->pgaceTuplePerms
+  * are reserved by rowacl. These bits are also stored within
+  * pgaceTuplePerms, we have to avoid to use the lower bits.
+  */
+ #define SEPGSQL_PERMS_USE                (1UL <<  8)
+ #define SEPGSQL_PERMS_SELECT            (1UL <<  9)
+ #define SEPGSQL_PERMS_UPDATE            (1UL << 10)
+ #define SEPGSQL_PERMS_INSERT            (1UL << 11)
+ #define SEPGSQL_PERMS_DELETE            (1UL << 12)
+ #define SEPGSQL_PERMS_RELABELFROM        (1UL << 13)
+ #define SEPGSQL_PERMS_RELABELTO            (1UL << 14)
+ #define SEPGSQL_PERMS_READ                (1UL << 15)
+ #define SEPGSQL_PERMS_MASK                (0xffffff00)
+
+ /*
+  * The implementation of PGACE/SE-PostgreSQL hooks
+  */
+
+ /* Initialize / Finalize related hooks */
+ extern Size sepgsqlShmemSize(void);
+
+ extern void sepgsqlInitialize(bool is_bootstrap);
+
+ extern pid_t sepgsqlStartupWorkerProcess(void);
+
+ /* SQL proxy hooks */
+ extern List *sepgsqlPostQueryRewrite(List *queryList);
+
+ extern void sepgsqlExecutorStart(QueryDesc *queryDesc, int eflags);
+
+ extern void sepgsqlProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel);
+
+ /* ExecScan hooks */
+ extern bool sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot);
+
+ /* HeapTuple modification hooks */
+ extern bool sepgsqlHeapTupleInsert(Relation rel, HeapTuple tuple,
+                                    bool is_internal, bool with_returning);
+ extern bool sepgsqlHeapTupleUpdate(Relation rel, ItemPointer otid,
+                                    HeapTuple newtup, bool is_internal,
+                                    bool with_returning);
+ extern bool sepgsqlHeapTupleDelete(Relation rel, ItemPointer otid,
+                                    bool is_internal, bool with_returning);
+
+ /*    Extended SQL statement hooks */
+ extern bool sepgsqlIsGramSecurityItem(DefElem *defel);
+
+ extern void sepgsqlGramCreateRelation(Relation rel, HeapTuple tuple,
+                                       DefElem *defel);
+ extern void sepgsqlGramCreateAttribute(Relation rel, HeapTuple tuple,
+                                        DefElem *defel);
+ extern void sepgsqlGramAlterRelation(Relation rel, HeapTuple tuple,
+                                      DefElem *defel);
+ extern void sepgsqlGramAlterAttribute(Relation rel, HeapTuple tuple,
+                                       DefElem *defel);
+ extern void sepgsqlGramCreateDatabase(Relation rel, HeapTuple tuple,
+                                       DefElem *defel);
+ extern void sepgsqlGramAlterDatabase(Relation rel, HeapTuple tuple,
+                                      DefElem *defel);
+ extern void sepgsqlGramCreateFunction(Relation rel, HeapTuple tuple,
+                                       DefElem *defel);
+ extern void sepgsqlGramAlterFunction(Relation rel, HeapTuple tuple,
+                                      DefElem *defel);
+
+ /* DATABASE related hooks */
+ extern void sepgsqlSetDatabaseParam(const char *name, char *argstring);
+
+ extern void sepgsqlGetDatabaseParam(const char *name);
+
+ /* FUNCTION related hooks */
+ extern void sepgsqlCallFunction(FmgrInfo *finfo);
+
+ extern void sepgsqlCallAggFunction(HeapTuple aggTuple);
+
+ extern bool sepgsqlCallTriggerFunction(TriggerData *tgdata);
+
+ extern Datum sepgsqlBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid);
+
+ extern void sepgsqlEndPerformCheckFK(Relation rel, Datum save_pgace);
+
+ extern bool sepgsqlAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple);
+
+ /* TABLE related hooks */
+ extern void sepgsqlLockTable(Oid relid);
+
+ extern void sepgsqlExecTruncate(List *trunc_rels);
+
+ extern bool sepgsqlAlterTable(Relation rel, AlterTableCmd *cmd);
+
+ /* COPY TO/COPY FROM statement hooks */
+ extern void sepgsqlCopyTable(Relation rel, List *attnumlist, bool is_from);
+
+ extern void sepgsqlCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom);
+
+ extern bool sepgsqlCopyToTuple(Relation rel, List *attnumlist, HeapTuple tuple);
+
+ /* Loadable shared library module hooks */
+ extern void sepgsqlLoadSharedModule(const char *filename);
+
+ /* Binary Large Object (BLOB) hooks */
+ extern void sepgsqlLargeObjectCreate(Relation rel, HeapTuple tuple);
+
+ extern void sepgsqlLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem);
+
+ extern void sepgsqlLargeObjectRead(LargeObjectDesc *lodesc, int length);
+
+ extern void sepgsqlLargeObjectWrite(LargeObjectDesc *lodesc, int length);
+
+ extern void sepgsqlLargeObjectTruncate(LargeObjectDesc *lodesc, int offset);
+
+ extern void sepgsqlLargeObjectImport(Oid loid, int fdesc, const char *filename);
+
+ extern void sepgsqlLargeObjectExport(Oid loid, int fdesc, const char *filename);
+
+ extern void sepgsqlLargeObjectGetSecurity(Relation rel, HeapTuple tuple);
+
+ extern void sepgsqlLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup);
+
+ /* Security Label hooks */
+ extern bool  sepgsqlTupleDescHasSecLabel(Relation rel, List *relopts);
+
+ extern char *sepgsqlTranslateSecurityLabelIn(const char *context);
+
+ extern char *sepgsqlTranslateSecurityLabelOut(const char *context);
+
+ extern bool  sepgsqlCheckValidSecurityLabel(char *context);
+
+ extern char *sepgsqlUnlabeledSecurityLabel(void);
+
+ extern char *sepgsqlSecurityLabelOfLabel(void);
+
+ /*
+  * SE-PostgreSQL core functions
+  *     src/backend/security/sepgsql/core.c
+  */
+ extern bool sepgsqlIsEnabled(void);
+
+ extern const security_context_t sepgsqlGetServerContext(void);
+
+ extern const security_context_t sepgsqlGetClientContext(void);
+
+ extern const security_context_t sepgsqlGetDatabaseContext(void);
+
+ extern const security_context_t sepgsqlGetUnlabeledContext(void);
+
+ extern const security_context_t sepgsqlSwitchClientContext(security_context_t newcon);
+
+ extern Oid sepgsqlGetDatabaseSecurityId(void);
+
+ /*
+  * SE-PostgreSQL userspace avc functions
+  *   src/backend/security/sepgsql/avc.c
+  */
+ extern void sepgsqlAvcInit(void);
+
+ extern void sepgsqlAvcSwitchClientContext(security_context_t context);
+
+ extern void sepgsqlClientHasPermission(Oid target_security_id,
+                                        security_class_t tclass,
+                                        access_vector_t perms,
+                                        const char *objname);
+
+ extern bool sepgsqlClientHasPermissionNoAbort(Oid target_security_id,
+                                               security_class_t tclass,
+                                               access_vector_t perms,
+                                               const char *objname);
+
+ extern Oid sepgsqlClientCreateSid(Oid target_security_id,
+                                   security_class_t tclass);
+
+ extern security_context_t
+ sepgsqlClientCreateContext(Oid target_security_id,
+                            security_class_t tclass);
+
+ extern bool sepgsqlComputePermission(const security_context_t scontext,
+                                      const security_context_t tcontext,
+                                      security_class_t tclass,
+                                      access_vector_t perms,
+                                      const char *objname);
+
+ extern security_context_t
+ sepgsqlComputeCreateContext(const security_context_t scontext,
+                             const security_context_t tcontext,
+                             security_class_t tclass);
+
+ /*
+  * SE-PostgreSQL permission evaluation related
+  *     src/backend/security/sepgsql/permission.c
+  */
+ extern const char *sepgsqlTupleName(Oid relid, HeapTuple tuple);
+
+ extern security_class_t sepgsqlFileObjectClass(int fdesc, const char *filename);
+
+ extern security_class_t sepgsqlTupleObjectClass(Oid relid, HeapTuple tuple);
+
+ extern void sepgsqlSetDefaultContext(Relation rel, HeapTuple tuple);
+
+ extern bool sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple newtup,
+                                    uint32 perms, bool abort);
+
+ extern void sepgsqlCheckModuleInstallPerms(const char *filename);
+
+ /*
+  * workaround for older libselinux
+  */
+ #ifndef DB_PROCEDURE__INSTALL
+ #define DB_PROCEDURE__INSTALL        0x00000100UL
+ #endif
+
+ #endif   /* SEPGSQL_H */
diff -Nrpc base/src/include/storage/fd.h sepgsql/src/include/storage/fd.h
*** base/src/include/storage/fd.h    Tue Jan 13 09:22:28 2009
--- sepgsql/src/include/storage/fd.h    Tue Jan 13 09:39:35 2009
*************** extern int    FileWrite(File file, char *bu
*** 68,73 ****
--- 68,74 ----
  extern int    FileSync(File file);
  extern off_t FileSeek(File file, off_t offset, int whence);
  extern int    FileTruncate(File file, off_t offset);
+ extern int  FileRawDescriptor(File file);

  /* Operations that allow use of regular stdio --- USE WITH CAUTION */
  extern FILE *AllocateFile(const char *name, const char *mode);
diff -Nrpc base/src/include/storage/lwlock.h sepgsql/src/include/storage/lwlock.h
*** base/src/include/storage/lwlock.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/storage/lwlock.h    Sat Jan  3 15:58:18 2009
*************** typedef enum LWLockId
*** 68,73 ****
--- 68,74 ----
      AutovacuumLock,
      AutovacuumScheduleLock,
      SyncScanLock,
+     SepgsqlAvcLock,
      /* Individual lock IDs end here */
      FirstBufMappingLock,
      FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS,
diff -Nrpc base/src/include/utils/acl.h sepgsql/src/include/utils/acl.h
*** base/src/include/utils/acl.h    Fri Jan 23 10:23:37 2009
--- sepgsql/src/include/utils/acl.h    Fri Jan 23 10:55:35 2009
*************** typedef struct
*** 222,227 ****
--- 222,228 ----
  /*
   * routines used internally
   */
+ extern Acl *allocacl(int n);
  extern Acl *acldefault(GrantObjectType objtype, Oid ownerId);
  extern Acl *aclupdate(const Acl *old_acl, const AclItem *mod_aip,
            int modechg, Oid ownerId, DropBehavior behavior);
*************** extern bool has_privs_of_role(Oid member
*** 237,242 ****
--- 238,244 ----
  extern bool is_member_of_role(Oid member, Oid role);
  extern bool is_member_of_role_nosuper(Oid member, Oid role);
  extern bool is_admin_of_role(Oid member, Oid role);
+ extern void check_acl(const Acl *acl);
  extern void check_is_member_of_role(Oid member, Oid role);

  extern void select_best_grantor(Oid roleId, AclMode privileges,
*************** extern AclResult pg_tablespace_aclcheck(
*** 295,300 ****
--- 297,307 ----
  extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode);
  extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode);

+ extern Acl *merge_acl_with_grant(Acl *old_acl, bool is_grant,
+                                  bool grant_option, DropBehavior behavior,
+                                  List *grantees, AclMode privileges,
+                                  Oid grantorId, Oid ownerId);
+
  extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
                 const char *objectname);

diff -Nrpc base/src/include/utils/catcache.h sepgsql/src/include/utils/catcache.h
*** base/src/include/utils/catcache.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/utils/catcache.h    Sat Jan  3 15:58:18 2009
*************** extern HeapTuple SearchCatCache(CatCache
*** 172,177 ****
--- 172,178 ----
                 Datum v1, Datum v2,
                 Datum v3, Datum v4);
  extern void ReleaseCatCache(HeapTuple tuple);
+ extern void InsertCatCache(CatCache *cache, HeapTuple tuple);

  extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys,
                     Datum v1, Datum v2,
diff -Nrpc base/src/include/utils/errcodes.h sepgsql/src/include/utils/errcodes.h
*** base/src/include/utils/errcodes.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/utils/errcodes.h    Sat Jan  3 15:58:18 2009
***************
*** 346,351 ****
--- 346,358 ----
  #define ERRCODE_NO_DATA_FOUND                MAKE_SQLSTATE('P','0', '0','0','2')
  #define ERRCODE_TOO_MANY_ROWS                MAKE_SQLSTATE('P','0', '0','0','3')

+ /* Class SE - Security Error (PGACE/SE-PostgreSQL error class) */
+ #define ERRCODE_PGACE_ERROR                    MAKE_SQLSTATE('S','E', '0','0','0')
+ #define ERRCODE_ROWACL_ERROR                MAKE_SQLSTATE('S','E', '0','1','1')
+ #define ERRCODE_SELINUX_ERROR                MAKE_SQLSTATE('S','E', '0','2','1')
+ #define ERRCODE_SELINUX_AUDIT                MAKE_SQLSTATE('S','E', '0','2','2')
+ #define ERRCODE_SELINUX_INFO                MAKE_SQLSTATE('S','E', '0','2','3')
+
  /* Class XX - Internal Error (PostgreSQL-specific error class) */
  /* (this is for "can't-happen" conditions and software bugs) */
  #define ERRCODE_INTERNAL_ERROR                MAKE_SQLSTATE('X','X', '0','0','0')
diff -Nrpc base/src/include/utils/rel.h sepgsql/src/include/utils/rel.h
*** base/src/include/utils/rel.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/utils/rel.h    Fri Jan  9 10:54:34 2009
*************** typedef struct StdRdOptions
*** 218,223 ****
--- 218,225 ----
  {
      int32        vl_len_;        /* varlena header (do not touch directly!) */
      int            fillfactor;        /* page fill factor in percent (0..100) */
+     bool        row_level_acl;    /* validator of Row-level ACLs */
+     int            default_row_acl;/* dafault Row-level ACLs */
  } StdRdOptions;

  #define HEAP_MIN_FILLFACTOR            10
*************** typedef struct StdRdOptions
*** 232,237 ****
--- 234,255 ----
       ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))

  /*
+  * RelationGetRowLevelAcl
+  *        Returns the relations's avairability of Row-level ACLs.
+  */
+ #define RelationGetRowLevelAcl(relation)                                \
+     ((relation)->rd_options ?                                            \
+      ((StdRdOptions *) (relation)->rd_options)->row_level_acl : false)
+
+ /*
+  * RelationGetDefaultAcl
+  *        Returns the relations's default Row-level ACLs in text
+  */
+ #define RelationGetDefaultRowAcl(relation)                                \
+     ((relation)->rd_options ?                                            \
+      GET_STRING_RELOPTION(((StdRdOptions *) (relation)->rd_options), default_row_acl) : NULL)
+
+ /*
   * RelationGetTargetPageUsage
   *        Returns the relation's desired space usage per page in bytes.
   */
diff -Nrpc base/src/include/utils/syscache.h sepgsql/src/include/utils/syscache.h
*** base/src/include/utils/syscache.h    Sat Jan  3 12:25:21 2009
--- sepgsql/src/include/utils/syscache.h    Sat Jan  3 15:58:18 2009
*************** enum SysCacheIdentifier
*** 69,74 ****
--- 69,76 ----
      RELNAMENSP,
      RELOID,
      RULERELNAME,
+     SECURITYOID,
+     SECURITYLABEL,
      STATRELATT,
      TSCONFIGMAP,
      TSCONFIGNAMENSP,
*************** extern HeapTuple SearchSysCache(int cach
*** 92,97 ****
--- 94,101 ----
                 Datum key1, Datum key2, Datum key3, Datum key4);
  extern void ReleaseSysCache(HeapTuple tuple);

+ extern void InsertSysCache(Oid relid, HeapTuple tuple);
+
  /* convenience routines */
  extern HeapTuple SearchSysCacheCopy(int cacheId,
                     Datum key1, Datum key2, Datum key3, Datum key4);

pgsql-hackers by date:

Previous
From: Gregory Stark
Date:
Subject: Re: V4 of PITR performance improvement for 8.4
Next
From: KaiGai Kohei
Date:
Subject: Re: SE-PostgreSQL Updated Revision (r1460)