From 6bd3a519b5ff79c53fcb90c3a1d3c01537843134 Mon Sep 17 00:00:00 2001 From: Jesse Keating Date: Fri, 7 Nov 2008 03:55:42 +0000 Subject: [PATCH 1/7] Initialize branch F-10 for sepostgresql --- branch | 1 + 1 file changed, 1 insertion(+) create mode 100644 branch diff --git a/branch b/branch new file mode 100644 index 0000000..dc32377 --- /dev/null +++ b/branch @@ -0,0 +1 @@ +F-10 From e2c95453954101a31a44b3d97f772fcaef34fa2e Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Fri, 6 Feb 2009 02:32:18 +0000 Subject: [PATCH 2/7] upgrade base postgresql 8.3.5->8.3.6 --- .cvsignore | 2 +- ...atch => sepostgresql-pg_dump-8.3.6-2.patch | 83 +- ...patch => sepostgresql-policy-8.3.6-2.patch | 63 +- ...atch => sepostgresql-sepgsql-8.3.6-2.patch | 8112 ++++++++++------- sepostgresql.init | 8 +- sepostgresql.spec | 14 +- sources | 2 +- 7 files changed, 4702 insertions(+), 3582 deletions(-) rename sepostgresql-pg_dump-8.3.5-2.patch => sepostgresql-pg_dump-8.3.6-2.patch (86%) rename sepostgresql-policy-8.3.5-2.patch => sepostgresql-policy-8.3.6-2.patch (96%) rename sepostgresql-sepgsql-8.3.5-2.patch => sepostgresql-sepgsql-8.3.6-2.patch (67%) diff --git a/.cvsignore b/.cvsignore index 9644800..a91c3f6 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -postgresql-8.3.5.tar.bz2 +postgresql-8.3.6.tar.bz2 diff --git a/sepostgresql-pg_dump-8.3.5-2.patch b/sepostgresql-pg_dump-8.3.6-2.patch similarity index 86% rename from sepostgresql-pg_dump-8.3.5-2.patch rename to sepostgresql-pg_dump-8.3.6-2.patch index b2dd54f..adea1a2 100644 --- a/sepostgresql-pg_dump-8.3.5-2.patch +++ b/sepostgresql-pg_dump-8.3.6-2.patch @@ -1,3 +1,52 @@ +diff -rpNU3 base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c +--- base/src/bin/initdb/initdb.c 2008-11-05 09:57:00.000000000 +0900 ++++ sepgsql/src/bin/initdb/initdb.c 2008-12-28 01:19:14.000000000 +0900 +@@ -94,6 +94,7 @@ static bool debug = false; + static bool noclean = false; + static bool show_setting = false; + static char *xlog_dir = ""; ++static char *pgace_feature = "none"; + + + /* internal vars */ +@@ -1212,6 +1213,11 @@ setup_config(void) + "#default_text_search_config = 'pg_catalog.simple'", + repltok); + ++ snprintf(repltok, sizeof(repltok), ++ "pgace_feature = '%s'", pgace_feature); ++ conflines = replace_token(conflines, ++ "#pgace_feature = 'none'", repltok); ++ + snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); + + writefile(path, conflines); +@@ -2383,6 +2389,7 @@ usage(const char *progname) + printf(_(" -U, --username=NAME database superuser name\n")); + printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); + printf(_(" --pwfile=FILE read password for the new superuser from file\n")); ++ printf(_(" --pgace-feature=FEATURE specify an enhanced security feature\n")); + printf(_(" -?, --help show this help, then exit\n")); + printf(_(" -V, --version output version information, then exit\n")); + printf(_("\nLess commonly used options:\n")); +@@ -2417,6 +2424,7 @@ main(int argc, char *argv[]) + {"auth", required_argument, NULL, 'A'}, + {"pwprompt", no_argument, NULL, 'W'}, + {"pwfile", required_argument, NULL, 9}, ++ {"pgace-feature", required_argument, NULL, 10}, + {"username", required_argument, NULL, 'U'}, + {"help", no_argument, NULL, '?'}, + {"version", no_argument, NULL, 'V'}, +@@ -2531,6 +2539,9 @@ main(int argc, char *argv[]) + case 9: + pwfilename = xstrdup(optarg); + break; ++ case 10: ++ pgace_feature = xstrdup(optarg); ++ break; + case 's': + show_setting = true; + break; diff -rpNU3 base/src/bin/pg_dump/pg_ace_dump.h sepgsql/src/bin/pg_dump/pg_ace_dump.h --- base/src/bin/pg_dump/pg_ace_dump.h 1970-01-01 09:00:00.000000000 +0900 +++ sepgsql/src/bin/pg_dump/pg_ace_dump.h 2008-10-14 15:38:18.000000000 +0900 @@ -287,8 +336,8 @@ diff -rpNU3 base/src/bin/pg_dump/pg_ace_dump.h sepgsql/src/bin/pg_dump/pg_ace_du + +#endif diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c ---- base/src/bin/pg_dump/pg_dump.c 2008-02-03 01:11:28.000000000 +0900 -+++ sepgsql/src/bin/pg_dump/pg_dump.c 2008-07-11 14:10:51.000000000 +0900 +--- base/src/bin/pg_dump/pg_dump.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/bin/pg_dump/pg_dump.c 2009-02-02 11:58:34.000000000 +0900 @@ -50,6 +50,7 @@ int optreset; #include "pg_backup_archiver.h" @@ -340,7 +389,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c printf(_("\nConnection options:\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); -@@ -1160,7 +1169,8 @@ dumpTableData_insert(Archive *fout, void +@@ -1171,7 +1180,8 @@ dumpTableData_insert(Archive *fout, void if (fout->remoteVersion >= 70100) { appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " @@ -350,7 +399,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, classname)); } -@@ -1774,11 +1784,14 @@ dumpBlobComments(Archive *AH, void *arg) +@@ -1785,11 +1795,14 @@ dumpBlobComments(Archive *AH, void *arg) Oid blobOid; char *comment; @@ -366,7 +415,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c comment = PQgetvalue(res, i, 1); printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ", -@@ -2926,6 +2939,7 @@ getTables(int *numTables) +@@ -2927,6 +2940,7 @@ getTables(int *numTables) "d.refobjsubid as owning_col, " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " "array_to_string(c.reloptions, ', ') as reloptions " @@ -374,7 +423,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c "from pg_class c " "left join pg_depend d on " "(c.relkind = '%c' and " -@@ -2935,6 +2949,7 @@ getTables(int *numTables) +@@ -2936,6 +2950,7 @@ getTables(int *numTables) "where relkind in ('%c', '%c', '%c', '%c') " "order by c.oid", username_subquery, @@ -382,7 +431,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c RELKIND_SEQUENCE, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); -@@ -3131,6 +3146,7 @@ getTables(int *numTables) +@@ -3132,6 +3147,7 @@ getTables(int *numTables) } tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace)); tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions)); @@ -390,7 +439,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c /* other fields were zeroed above */ -@@ -4362,11 +4378,13 @@ getTableAttrs(TableInfo *tblinfo, int nu +@@ -4363,11 +4379,13 @@ getTableAttrs(TableInfo *tblinfo, int nu appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, " "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, " "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname " @@ -404,7 +453,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c tbinfo->dobj.catId.oid); } else if (g_fout->remoteVersion >= 70100) -@@ -4425,6 +4443,7 @@ getTableAttrs(TableInfo *tblinfo, int nu +@@ -4426,6 +4444,7 @@ getTableAttrs(TableInfo *tblinfo, int nu tbinfo->typstorage = (char *) malloc(ntups * sizeof(char)); tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool)); tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool)); @@ -412,7 +461,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool)); tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *)); tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); -@@ -4456,6 +4475,8 @@ getTableAttrs(TableInfo *tblinfo, int nu +@@ -4457,6 +4476,8 @@ getTableAttrs(TableInfo *tblinfo, int nu tbinfo->inhAttrs[j] = false; tbinfo->inhAttrDef[j] = false; tbinfo->inhNotNull[j] = false; @@ -421,7 +470,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c } PQclear(res); -@@ -6459,8 +6480,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo) +@@ -6460,8 +6481,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "provolatile, proisstrict, prosecdef, " "proconfig, procost, prorows, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname " @@ -432,7 +481,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c finfo->dobj.catId.oid); } else if (g_fout->remoteVersion >= 80100) -@@ -6698,6 +6721,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) +@@ -6699,6 +6722,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) if (prosecdef[0] == 't') appendPQExpBuffer(q, " SECURITY DEFINER"); @@ -441,7 +490,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c /* * COST and ROWS are emitted only if present and not default, so as not to * break backwards-compatibility of the dump without need. Keep this code -@@ -8779,6 +8804,8 @@ dumpTableSchema(Archive *fout, TableInfo +@@ -8780,6 +8805,8 @@ dumpTableSchema(Archive *fout, TableInfo if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j]) appendPQExpBuffer(q, " NOT NULL"); @@ -450,7 +499,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c actual_atts++; } } -@@ -8826,6 +8853,8 @@ dumpTableSchema(Archive *fout, TableInfo +@@ -8827,6 +8854,8 @@ dumpTableSchema(Archive *fout, TableInfo if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions); @@ -459,7 +508,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c appendPQExpBuffer(q, ";\n"); /* Loop dumping statistics and storage statements */ -@@ -10243,6 +10272,10 @@ fmtCopyColumnList(const TableInfo *ti) +@@ -10244,6 +10273,10 @@ fmtCopyColumnList(const TableInfo *ti) appendPQExpBuffer(q, "("); needComma = false; @@ -471,8 +520,8 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c { if (attisdropped[i]) diff -rpNU3 base/src/bin/pg_dump/pg_dump.h sepgsql/src/bin/pg_dump/pg_dump.h ---- base/src/bin/pg_dump/pg_dump.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/bin/pg_dump/pg_dump.h 2008-06-15 22:27:55.000000000 +0900 +--- base/src/bin/pg_dump/pg_dump.h 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/bin/pg_dump/pg_dump.h 2009-02-02 11:58:34.000000000 +0900 @@ -238,6 +238,7 @@ typedef struct _tableInfo char relkind; char *reltablespace; /* relation tablespace */ diff --git a/sepostgresql-policy-8.3.5-2.patch b/sepostgresql-policy-8.3.6-2.patch similarity index 96% rename from sepostgresql-policy-8.3.5-2.patch rename to sepostgresql-policy-8.3.6-2.patch index e7db11d..067e34f 100644 --- a/sepostgresql-policy-8.3.5-2.patch +++ b/sepostgresql-policy-8.3.6-2.patch @@ -103,9 +103,9 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.if sepgs +## There are no interface declaration diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te --- base/src/backend/security/sepgsql/policy/sepostgresql-devel.te 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2008-10-13 17:08:55.000000000 +0900 -@@ -0,0 +1,127 @@ -+policy_module(sepostgresql-devel, 3.14) ++++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-01-20 16:35:05.000000000 +0900 +@@ -0,0 +1,120 @@ ++policy_module(sepostgresql-devel, 3.23) + +gen_require(` + class db_database all_db_database_perms; @@ -115,7 +115,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgs + class db_tuple all_db_tuple_perms; + class db_blob all_db_blob_perms; + -+ attribute domain, home_type, tmpfile; + attribute sepgsql_client_type; + attribute sepgsql_unconfined_type; + @@ -126,7 +125,13 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgs + attribute sepgsql_blob_type; + attribute sepgsql_module_type; + ++ # for regression test ++ type bin_t; ++ type user_home_t; + type sepgsql_trusted_proc_t; ++ ++ attribute tmpfile; ++ attribute user_ptynode; +') + +################################# @@ -134,44 +139,30 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgs +# Domain for Testcases +# + -+type sepgsql_test_t; -+domain_type(sepgsql_test_t) ++role sepgsql_test_r; ++ ++userdom_unpriv_user_template(sepgsql_test) ++ ++ifdef(`postgresql_role', ` ++ postgresql_role(sepgsql_test_r, sepgsql_test_t) ++',` ++ postgresql_userdom_template(sepgsql_test, sepgsql_test_t, sepgsql_test_r) ++') ++ ++allow sepgsql_test_t tmpfile : dir search_dir_perms; ++allow sepgsql_test_t tmpfile : file rw_file_perms; ++allow sepgsql_test_t user_ptynode : chr_file rw_file_perms; + +optional_policy(` + gen_require(` -+ role unconfined_r; + type unconfined_t; ++ role unconfined_r; + ') + allow unconfined_t sepgsql_test_t : process transition; + role unconfined_r types sepgsql_test_t; + role unconfined_r types sepgsql_trusted_proc_t; +') + -+corecmd_exec_bin(sepgsql_test_t) -+allow sepgsql_test_t bin_t : file { entrypoint }; -+ -+files_read_usr_files(sepgsql_test_t) -+files_read_etc_files(sepgsql_test_t) -+libs_use_ld_so(sepgsql_test_t) -+libs_use_shared_libs(sepgsql_test_t) -+ -+term_use_all_terms(sepgsql_test_t) -+ -+files_search_home(sepgsql_test_t) -+allow sepgsql_test_t home_type : file rw_file_perms; -+allow sepgsql_test_t home_type : dir search_dir_perms; -+miscfiles_read_localization(sepgsql_test_t) -+ -+allow sepgsql_test_t tmpfile : dir search_dir_perms; -+allow sepgsql_test_t tmpfile : file rw_file_perms; -+ -+postgresql_stream_connect(sepgsql_test_t) -+postgresql_unpriv_client(sepgsql_test_t) -+ -+optional_policy(` -+ nscd_shm_use(sepgsql_test_t) -+') -+ +################################# +# +# SE-PostgreSQL Declarations @@ -207,6 +198,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgs + auditallow domain sepgsql_database_type : db_database *; + auditallow domain sepgsql_table_type : db_table *; + auditallow domain sepgsql_table_type : db_column *; ++ auditallow domain sepgsql_table_type : db_tuple { relabelfrom relabelto }; + auditallow domain sepgsql_procedure_type : db_procedure *; + auditallow domain sepgsql_blob_type : db_blob *; + auditallow domain sepgsql_module_type : db_database { install_module }; @@ -217,6 +209,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgs + dontaudit domain sepgsql_database_type : db_database *; + dontaudit domain sepgsql_table_type : db_table *; + dontaudit domain sepgsql_table_type : db_column *; ++ dontaudit domain sepgsql_table_type : db_tuple { relabelfrom relabelto }; + dontaudit domain sepgsql_procedure_type : db_procedure *; + dontaudit domain sepgsql_blob_type : db_blob *; + dontaudit domain sepgsql_module_type : db_database { install_module }; @@ -228,9 +221,9 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgs +# SE-PostgreSQL regression test mode switch +# +tunable_policy(`sepgsql_regression_test_mode',` -+ allow sepgsql_client_type home_type : db_database { install_module }; -+ allow sepgsql_unconfined_type home_type : db_database { install_module }; -+ allow sepgsql_database_type home_type : db_database { load_module }; ++ allow sepgsql_client_type user_home_t : db_database { install_module }; ++ allow sepgsql_unconfined_type user_home_t : db_database { install_module }; ++ allow sepgsql_database_type user_home_t : db_database { load_module }; +') diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql.fc.template sepgsql/src/backend/security/sepgsql/policy/sepostgresql.fc.template --- base/src/backend/security/sepgsql/policy/sepostgresql.fc.template 1970-01-01 09:00:00.000000000 +0900 diff --git a/sepostgresql-sepgsql-8.3.5-2.patch b/sepostgresql-sepgsql-8.3.6-2.patch similarity index 67% rename from sepostgresql-sepgsql-8.3.5-2.patch rename to sepostgresql-sepgsql-8.3.6-2.patch index 1739847..b036880 100644 --- a/sepostgresql-sepgsql-8.3.5-2.patch +++ b/sepostgresql-sepgsql-8.3.6-2.patch @@ -1,6 +1,6 @@ diff -rpNU3 base/configure sepgsql/configure ---- base/configure 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql/configure 2008-11-05 10:01:30.000000000 +0900 +--- base/configure 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/configure 2009-02-02 11:58:34.000000000 +0900 @@ -314,7 +314,7 @@ ac_includes_default="\ # include #endif" @@ -18,7 +18,7 @@ diff -rpNU3 base/configure sepgsql/configure --disable-largefile omit support for large files Optional Packages: -@@ -4619,6 +4620,120 @@ fi; +@@ -4619,6 +4620,115 @@ fi; # @@ -51,7 +51,7 @@ diff -rpNU3 base/configure sepgsql/configure +fi; + +if test "$enable_selinux" = yes; then -+ echo "$as_me:$LINENO: checking for getpeercon in -lselinux" >&5 ++ 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 @@ -117,11 +117,6 @@ diff -rpNU3 base/configure sepgsql/configure +echo "${ECHO_T}$ac_cv_lib_selinux_getpeercon" >&6 +if test $ac_cv_lib_selinux_getpeercon = yes; then + -+cat >>confdefs.h <<\_ACEOF -+#define SECURITY_SYSATTR_NAME "security_context" -+_ACEOF -+ -+ +cat >>confdefs.h <<_ACEOF +#define HAVE_SELINUX 1 +_ACEOF @@ -139,7 +134,7 @@ diff -rpNU3 base/configure sepgsql/configure # Elf # -@@ -26006,6 +26121,7 @@ s,@with_libxml@,$with_libxml,;t t +@@ -26019,6 +26129,7 @@ s,@with_libxml@,$with_libxml,;t t s,@with_libxslt@,$with_libxslt,;t t s,@with_system_tzdata@,$with_system_tzdata,;t t s,@with_zlib@,$with_zlib,;t t @@ -148,9 +143,9 @@ diff -rpNU3 base/configure sepgsql/configure s,@ELF_SYS@,$ELF_SYS,;t t s,@LDFLAGS_SL@,$LDFLAGS_SL,;t t diff -rpNU3 base/configure.in sepgsql/configure.in ---- base/configure.in 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql/configure.in 2008-11-05 10:01:30.000000000 +0900 -@@ -626,6 +626,21 @@ PGAC_ARG_BOOL(with, zlib, yes, +--- base/configure.in 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/configure.in 2009-02-02 11:58:34.000000000 +0900 +@@ -626,6 +626,19 @@ PGAC_ARG_BOOL(with, zlib, yes, AC_SUBST(with_zlib) # @@ -159,13 +154,11 @@ diff -rpNU3 base/configure.in sepgsql/configure.in +PGAC_ARG_BOOL(enable, selinux, no, + [ --enable-selinux build with SELinux support]) +if test "$enable_selinux" = yes; then -+ AC_CHECK_LIB(selinux, getpeercon, -+ AC_DEFINE(SECURITY_SYSATTR_NAME, "security_context", -+ [Enables system column for security attribute support]) -+ AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1, -+ [Enables SE-PostgreSQL feature]) -+ AC_SUBST(enable_selinux), -+ AC_MSG_ERROR("--enable-selinux requires libselinux.")) ++ 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 + +# @@ -992,7 +985,7 @@ diff -rpNU3 base/src/backend/Makefile sepgsql/src/backend/Makefile all: submake-libpgport postgres $(POSTGRES_IMP) diff -rpNU3 base/src/backend/access/common/heaptuple.c sepgsql/src/backend/access/common/heaptuple.c --- base/src/backend/access/common/heaptuple.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/access/common/heaptuple.c 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/access/common/heaptuple.c 2008-12-28 01:06:59.000000000 +0900 @@ -67,6 +67,7 @@ #include "access/heapam.h" #include "access/tuptoaster.h" @@ -1001,135 +994,178 @@ diff -rpNU3 base/src/backend/access/common/heaptuple.c sepgsql/src/backend/acces /* Does att's datatype allow packing into the 1-byte-header varlena format? */ -@@ -473,6 +474,9 @@ heap_attisnull(HeapTuple tup, int attnum +@@ -473,6 +474,7 @@ heap_attisnull(HeapTuple tup, int attnum case MinCommandIdAttributeNumber: case MaxTransactionIdAttributeNumber: case MaxCommandIdAttributeNumber: -+#ifdef SECURITY_SYSATTR_NAME -+ case SecurityAttributeNumber: -+#endif ++ case SecurityLabelAttributeNumber: /* these are never null */ break; -@@ -785,6 +789,16 @@ heap_getsysattr(HeapTuple tup, int attnu +@@ -785,6 +787,9 @@ heap_getsysattr(HeapTuple tup, int attnu case TableOidAttributeNumber: result = ObjectIdGetDatum(tup->t_tableOid); break; -+#ifdef SECURITY_SYSATTR_NAME -+ case SecurityAttributeNumber: { -+ Oid security_id = HeapTupleGetSecurity(tup); -+ char *sec_label = pgaceSidToSecurityLabel(security_id); -+ -+ result = CStringGetTextDatum(sec_label); -+ pfree(sec_label); ++ case SecurityLabelAttributeNumber: ++ result = pgaceHeapGetSecurityLabelSysattr(tup); + break; -+ } -+#endif default: elog(ERROR, "invalid attnum: %d", attnum); result = 0; /* keep compiler quiet */ -@@ -909,6 +923,9 @@ heap_form_tuple(TupleDesc tupleDescripto +@@ -909,6 +914,9 @@ heap_form_tuple(TupleDesc tupleDescripto if (tupleDescriptor->tdhasoid) len += sizeof(Oid); -+ if (pgaceSecurityAttributeNecessary()) ++ if (tupleDescriptor->tdhasseclabel) + len += sizeof(Oid); + hoff = len = MAXALIGN(len); /* align user data safely */ data_len = heap_compute_data_size(tupleDescriptor, values, isnull); -@@ -940,6 +957,9 @@ heap_form_tuple(TupleDesc tupleDescripto +@@ -940,6 +948,9 @@ heap_form_tuple(TupleDesc tupleDescripto if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ td->t_infomask = HEAP_HASOID; -+ if (pgaceSecurityAttributeNecessary()) -+ td->t_infomask |= HEAP_HASSECURITY; ++ if (tupleDescriptor->tdhasseclabel) ++ td->t_infomask |= HEAP_HAS_SECLABEL; + heap_fill_tuple(tupleDescriptor, values, isnull, -@@ -1020,6 +1040,9 @@ heap_formtuple(TupleDesc tupleDescriptor +@@ -1020,6 +1031,9 @@ heap_formtuple(TupleDesc tupleDescriptor if (tupleDescriptor->tdhasoid) len += sizeof(Oid); -+ if (pgaceSecurityAttributeNecessary()) ++ if (tupleDescriptor->tdhasseclabel) + len += sizeof(Oid); + hoff = len = MAXALIGN(len); /* align user data safely */ data_len = ComputeDataSize(tupleDescriptor, values, nulls); -@@ -1051,6 +1074,9 @@ heap_formtuple(TupleDesc tupleDescriptor +@@ -1051,6 +1065,9 @@ heap_formtuple(TupleDesc tupleDescriptor if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ td->t_infomask = HEAP_HASOID; -+ if (pgaceSecurityAttributeNecessary()) -+ td->t_infomask |= HEAP_HASSECURITY; ++ if (tupleDescriptor->tdhasseclabel) ++ td->t_infomask |= HEAP_HAS_SECLABEL; + DataFill(tupleDescriptor, values, nulls, -@@ -1129,6 +1155,8 @@ heap_modify_tuple(HeapTuple tuple, +@@ -1129,6 +1146,8 @@ heap_modify_tuple(HeapTuple tuple, newTuple->t_tableOid = tuple->t_tableOid; if (tupleDesc->tdhasoid) HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); -+ if (HeapTupleHasSecurity(newTuple)) -+ HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple)); ++ if (HeapTupleHasSecLabel(newTuple)) ++ HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple)); return newTuple; } -@@ -1201,6 +1229,8 @@ heap_modifytuple(HeapTuple tuple, +@@ -1201,6 +1220,8 @@ heap_modifytuple(HeapTuple tuple, newTuple->t_tableOid = tuple->t_tableOid; if (tupleDesc->tdhasoid) HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); -+ if (HeapTupleHasSecurity(newTuple)) -+ HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple)); ++ if (HeapTupleHasSecLabel(newTuple)) ++ HeapTupleSetSecLabel(newTuple, HeapTupleGetSecLabel(tuple)); return newTuple; } -@@ -1847,6 +1877,9 @@ heap_form_minimal_tuple(TupleDesc tupleD +@@ -1847,6 +1868,9 @@ heap_form_minimal_tuple(TupleDesc tupleD if (tupleDescriptor->tdhasoid) len += sizeof(Oid); -+ if (pgaceSecurityAttributeNecessary()) ++ if (tupleDescriptor->tdhasseclabel) + len += sizeof(Oid); + hoff = len = MAXALIGN(len); /* align user data safely */ data_len = heap_compute_data_size(tupleDescriptor, values, isnull); -@@ -1868,6 +1901,9 @@ heap_form_minimal_tuple(TupleDesc tupleD +@@ -1868,6 +1892,9 @@ heap_form_minimal_tuple(TupleDesc tupleD if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ tuple->t_infomask = HEAP_HASOID; -+ if (pgaceSecurityAttributeNecessary()) -+ tuple->t_infomask |= HEAP_HASSECURITY; ++ if (tupleDescriptor->tdhasseclabel) ++ tuple->t_infomask |= HEAP_HAS_SECLABEL; + heap_fill_tuple(tupleDescriptor, values, isnull, -@@ -1979,6 +2015,10 @@ heap_addheader(int natts, /* max domain +@@ -1965,6 +1992,7 @@ minimal_tuple_from_heap_tuple(HeapTuple + HeapTuple + heap_addheader(int natts, /* max domain index */ + bool withoid, /* reserve space for oid */ ++ bool withsecurity, /* reserve space for security */ + Size structlen, /* its length */ + void *structure) /* pointer to the struct */ + { +@@ -1979,6 +2007,10 @@ heap_addheader(int natts, /* max domain hoff = offsetof(HeapTupleHeaderData, t_bits); if (withoid) hoff += sizeof(Oid); + -+ if (pgaceSecurityAttributeNecessary()) ++ if (withsecurity) + hoff += sizeof(Oid); + hoff = MAXALIGN(hoff); len = hoff + structlen; -@@ -1997,6 +2037,9 @@ heap_addheader(int natts, /* max domain +@@ -1997,6 +2029,9 @@ heap_addheader(int natts, /* max domain if (withoid) /* else leave infomask = 0 */ td->t_infomask = HEAP_HASOID; -+ if (pgaceSecurityAttributeNecessary()) -+ td->t_infomask |= HEAP_HASSECURITY; ++ if (withsecurity) ++ td->t_infomask |= HEAP_HAS_SECLABEL; + memcpy((char *) td + hoff, structure, structlen); return tuple; +diff -rpNU3 base/src/backend/access/common/tupdesc.c sepgsql/src/backend/access/common/tupdesc.c +--- base/src/backend/access/common/tupdesc.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/access/common/tupdesc.c 2008-12-28 01:06:59.000000000 +0900 +@@ -84,6 +84,7 @@ CreateTemplateTupleDesc(int natts, bool + desc->tdtypeid = RECORDOID; + desc->tdtypmod = -1; + desc->tdhasoid = hasoid; ++ desc->tdhasseclabel = false; /* set a proper value, if necessary */ + desc->tdrefcount = -1; /* assume not reference-counted */ + + return desc; +@@ -117,6 +118,7 @@ CreateTupleDesc(int natts, bool hasoid, + desc->tdtypeid = RECORDOID; + desc->tdtypmod = -1; + desc->tdhasoid = hasoid; ++ desc->tdhasseclabel = false; /* set a proper value, if necessary */ + desc->tdrefcount = -1; /* assume not reference-counted */ + + return desc; +@@ -146,6 +148,7 @@ CreateTupleDescCopy(TupleDesc tupdesc) + + desc->tdtypeid = tupdesc->tdtypeid; + desc->tdtypmod = tupdesc->tdtypmod; ++ desc->tdhasseclabel = tupdesc->tdhasseclabel; + + return desc; + } +@@ -204,6 +207,7 @@ CreateTupleDescCopyConstr(TupleDesc tupd + + desc->tdtypeid = tupdesc->tdtypeid; + desc->tdtypmod = tupdesc->tdtypmod; ++ desc->tdhasseclabel = tupdesc->tdhasseclabel; + + return desc; + } +@@ -310,6 +314,8 @@ equalTupleDescs(TupleDesc tupdesc1, Tupl + return false; + if (tupdesc1->tdhasoid != tupdesc2->tdhasoid) + return false; ++ if (tupdesc1->tdhasseclabel != tupdesc2->tdhasseclabel) ++ return false; + + for (i = 0; i < tupdesc1->natts; i++) + { diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/heap/heapam.c ---- base/src/backend/access/heap/heapam.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/access/heap/heapam.c 2008-09-25 15:22:04.000000000 +0900 +--- base/src/backend/access/heap/heapam.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/access/heap/heapam.c 2009-02-02 11:58:34.000000000 +0900 @@ -50,6 +50,7 @@ #include "catalog/namespace.h" #include "miscadmin.h" @@ -1138,39 +1174,48 @@ diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/hea #include "storage/procarray.h" #include "storage/smgr.h" #include "utils/datum.h" -@@ -1949,6 +1950,9 @@ heap_insert(Relation relation, HeapTuple +@@ -1949,6 +1950,12 @@ heap_insert(Relation relation, HeapTuple Oid simple_heap_insert(Relation relation, HeapTuple tup) { + if (!pgaceHeapTupleInsert(relation, tup, true, false)) -+ elog(ERROR, "simple_heap_insert on %s failed due to security reason", -+ RelationGetRelationName(relation)); ++ 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), true, true); } -@@ -2230,6 +2234,9 @@ simple_heap_delete(Relation relation, It +@@ -2230,6 +2237,12 @@ simple_heap_delete(Relation relation, It ItemPointerData update_ctid; TransactionId update_xmax; + if (!pgaceHeapTupleDelete(relation, tid, true, false)) -+ elog(ERROR, "simple_heap_delete on %s failed due to security reason", -+ RelationGetRelationName(relation)); ++ 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, -@@ -2873,6 +2880,9 @@ simple_heap_update(Relation relation, It +@@ -2874,6 +2887,12 @@ simple_heap_update(Relation relation, It ItemPointerData update_ctid; TransactionId update_xmax; + if (!pgaceHeapTupleUpdate(relation, otid, tup, true, false)) -+ elog(ERROR, "simple_heap_update on %s failed due to security reason", -+ RelationGetRelationName(relation)); ++ 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 -rpNU3 base/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access/heap/tuptoaster.c --- base/src/backend/access/heap/tuptoaster.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/access/heap/tuptoaster.c 2008-10-16 12:43:28.000000000 +0900 ++++ sepgsql/src/backend/access/heap/tuptoaster.c 2009-01-14 15:06:52.000000000 +0900 @@ -35,6 +35,7 @@ #include "access/tuptoaster.h" #include "access/xact.h" @@ -1183,7 +1228,7 @@ diff -rpNU3 base/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access hoff += BITMAPLEN(numAttrs); if (newtup->t_data->t_infomask & HEAP_HASOID) hoff += sizeof(Oid); -+ if (newtup->t_data->t_infomask & HEAP_HASSECURITY) ++ if (newtup->t_data->t_infomask & HEAP_HAS_SECLABEL) + hoff += sizeof(Oid); hoff = MAXALIGN(hoff); Assert(hoff == newtup->t_data->t_hoff); @@ -1192,7 +1237,7 @@ diff -rpNU3 base/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access new_len += BITMAPLEN(numAttrs); if (olddata->t_infomask & HEAP_HASOID) new_len += sizeof(Oid); -+ if (olddata->t_infomask & HEAP_HASSECURITY) ++ if (olddata->t_infomask & HEAP_HAS_SECLABEL) + new_len += sizeof(Oid); new_len = MAXALIGN(new_len); Assert(new_len == olddata->t_hoff); @@ -1201,24 +1246,50 @@ diff -rpNU3 base/src/backend/access/heap/tuptoaster.c sepgsql/src/backend/access new_len += BITMAPLEN(numAttrs); if (olddata->t_infomask & HEAP_HASOID) new_len += sizeof(Oid); -+ if (olddata->t_infomask & HEAP_HASSECURITY) ++ if (olddata->t_infomask & HEAP_HAS_SECLABEL) + new_len += sizeof(Oid); new_len = MAXALIGN(new_len); Assert(new_len == olddata->t_hoff); new_data_len = heap_compute_data_size(tupleDesc, -@@ -1173,6 +1180,8 @@ toast_save_datum(Relation rel, Datum val +@@ -1173,6 +1180,12 @@ toast_save_datum(Relation rel, Datum val memcpy(VARDATA(&chunk_data), data_p, chunk_size); toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull); + if (!pgaceHeapTupleInsert(toastrel, toasttup, true, false)) -+ elog(ERROR, "failed to insert TOAST tuple due to security reason"); ++ ereport(ERROR, ++ (errcode(ERRCODE_PGACE_ERROR), ++ errmsg("could not insert tuple \"%s\" due to pgace security", ++ RelationGetRelationName(toastrel)))); ++ heap_insert(toastrel, toasttup, mycid, use_wal, use_fsm); /* diff -rpNU3 base/src/backend/bootstrap/bootparse.y sepgsql/src/backend/bootstrap/bootparse.y --- base/src/backend/bootstrap/bootparse.y 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/bootstrap/bootparse.y 2008-06-14 02:36:58.000000000 +0900 -@@ -212,7 +212,8 @@ Boot_CreateStmt: ++++ sepgsql/src/backend/bootstrap/bootparse.y 2008-12-28 01:06:59.000000000 +0900 +@@ -42,6 +42,7 @@ + #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" +@@ -194,6 +195,13 @@ Boot_CreateStmt: + RELKIND_RELATION, + $3, + true); ++ /* ++ * fixup boot_reldesc->rd_att->tdhasseclabel ++ */ ++ boot_reldesc->rd_rel->relkind = RELKIND_RELATION; ++ boot_reldesc->rd_att->tdhasseclabel ++ = pgaceTupleDescHasSecLabel(boot_reldesc, NIL); ++ + elog(DEBUG4, "bootstrap relation created"); + } + else +@@ -212,7 +220,8 @@ Boot_CreateStmt: 0, ONCOMMIT_NOOP, (Datum) 0, @@ -1230,7 +1301,7 @@ diff -rpNU3 base/src/backend/bootstrap/bootparse.y sepgsql/src/backend/bootstrap do_end(); diff -rpNU3 base/src/backend/bootstrap/bootstrap.c sepgsql/src/backend/bootstrap/bootstrap.c --- base/src/backend/bootstrap/bootstrap.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/bootstrap/bootstrap.c 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/bootstrap/bootstrap.c 2008-12-28 01:06:59.000000000 +0900 @@ -31,6 +31,7 @@ #include "nodes/makefuncs.h" #include "postmaster/bgwriter.h" @@ -1248,6 +1319,14 @@ diff -rpNU3 base/src/backend/bootstrap/bootstrap.c sepgsql/src/backend/bootstrap /* Perform a checkpoint to ensure everything's down to disk */ SetProcessingMode(NormalProcessing); CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE); +@@ -796,6 +799,7 @@ InsertOneTuple(Oid objectid) + tupDesc = CreateTupleDesc(numattr, + RelationGetForm(boot_reldesc)->relhasoids, + attrtypes); ++ tupDesc->tdhasseclabel = pgaceTupleDescHasSecLabel(boot_reldesc, NIL); + tuple = heap_formtuple(tupDesc, values, Blanks); + if (objectid != (Oid) 0) + HeapTupleSetOid(tuple, objectid); diff -rpNU3 base/src/backend/catalog/Makefile sepgsql/src/backend/catalog/Makefile --- base/src/backend/catalog/Makefile 2007-09-11 10:53:53.000000000 +0900 +++ sepgsql/src/backend/catalog/Makefile 2008-06-14 02:36:58.000000000 +0900 @@ -1287,45 +1366,9 @@ diff -rpNU3 base/src/backend/catalog/catalog.c sepgsql/src/backend/catalog/catal relationId == SharedDescriptionObjIndexId || relationId == SharedDependDependerIndexId || relationId == SharedDependReferenceIndexId || -diff -rpNU3 base/src/backend/catalog/genbki.sh sepgsql/src/backend/catalog/genbki.sh ---- base/src/backend/catalog/genbki.sh 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/catalog/genbki.sh 2008-06-14 02:36:58.000000000 +0900 -@@ -130,6 +130,16 @@ for dir in $INCLUDE_DIRS; do - fi - done - -+# Get SECURITY_SYSATTR_NAME from pg_config.h -+SECURITY_SYSATTR_NAME_FILTERING="SECURITY_SYSATTR_NAME" -+for dir in $INCLUDE_DIRS; do -+ if [ -f "$dir/pg_config.h" ]; then -+ SECURITY_SYSATTR_NAME=`grep '#define[ ]*SECURITY_SYSATTR_NAME' $dir/pg_config.h | $AWK '{ print $3 }' | sed 's/\"//g'` -+ test -n "$SECURITY_SYSATTR_NAME" && SECURITY_SYSATTR_NAME_FILTERING="^__invalid__pattern__$" -+ break -+ fi -+done -+ - touch ${OUTPUT_PREFIX}.description.$$ - touch ${OUTPUT_PREFIX}.shdescription.$$ - -@@ -144,6 +154,7 @@ touch ${OUTPUT_PREFIX}.shdescription.$$ - # ---------------- - # - cat $INFILES | \ -+grep -v $SECURITY_SYSATTR_NAME_FILTERING | \ - sed -e 's;/\*.*\*/;;g' \ - -e 's;/\*;\ - /*\ -@@ -165,6 +176,7 @@ sed -e "s/;[ ]*$//g" \ - -e "s/PGUID/$BOOTSTRAP_SUPERUSERID/g" \ - -e "s/NAMEDATALEN/$NAMEDATALEN/g" \ - -e "s/PGNSP/$PG_CATALOG_NAMESPACE/g" \ -+ -e "s/SECURITY_SYSATTR_NAME/$SECURITY_SYSATTR_NAME/g" \ - | $AWK ' - # ---------------- - # now use awk to process remaining .h file.. diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c --- base/src/backend/catalog/heap.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/catalog/heap.c 2008-06-18 17:25:44.000000000 +0900 ++++ sepgsql/src/backend/catalog/heap.c 2008-12-28 01:06:59.000000000 +0900 @@ -53,6 +53,7 @@ #include "parser/parse_coerce.h" #include "parser/parse_expr.h" @@ -1344,29 +1387,22 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c static Oid AddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, -@@ -144,7 +146,21 @@ static FormData_pg_attribute a7 = { +@@ -144,7 +146,13 @@ static FormData_pg_attribute a7 = { true, 'p', 'i', true, false, false, true, 0 }; -+#ifdef SECURITY_SYSATTR_NAME -+/* -+ * SECURITY_SYSATTR_NAME is defined at PGACE header file. -+ * If SELinux is enabled, it is defined as "security_context" -+ */ +-static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; +static FormData_pg_attribute a8 = { -+ 0, {SECURITY_SYSATTR_NAME}, TEXTOID, 0, -1, -+ SecurityAttributeNumber, 0, -1, -1, ++ 0, {SecurityLabelAttributeName}, TEXTOID, 0, -1, ++ SecurityLabelAttributeNumber, 0, -1, -1, + false, 'x', 'i', true, false, false, true, 0 +}; + +static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8}; -+#else - static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; -+#endif /* * This function returns a Form_pg_attribute pointer for a system attribute. -@@ -184,6 +200,20 @@ SystemAttributeByName(const char *attnam +@@ -184,6 +192,18 @@ SystemAttributeByName(const char *attnam return NULL; } @@ -1375,19 +1411,17 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c + * system column. If not, returns false. + */ +bool -+SystemAttributeIsWritable(AttrNumber attno, bool relhasoids) ++SystemAttributeIsWritable(AttrNumber attnum) +{ -+#ifdef SECURITY_SYSATTR_NAME -+ if (pgaceSecurityAttributeNecessary() -+ && attno == SecurityAttributeNumber) ++ if (attnum == SecurityLabelAttributeNumber) + return true; -+#endif ++ + return false; +} /* ---------------------------------------------------------------- * XXX END OF UGLY HARD CODED BADNESS XXX -@@ -467,7 +497,8 @@ AddNewAttributeTuples(Oid new_rel_oid, +@@ -467,7 +487,8 @@ AddNewAttributeTuples(Oid new_rel_oid, TupleDesc tupdesc, char relkind, bool oidislocal, @@ -1397,15 +1431,26 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { const Form_pg_attribute *dpp; int i; -@@ -502,6 +533,7 @@ AddNewAttributeTuples(Oid new_rel_oid, +@@ -500,8 +521,10 @@ AddNewAttributeTuples(Oid new_rel_oid, + + tup = heap_addheader(Natts_pg_attribute, false, ++ RelationGetDescr(rel)->tdhasseclabel, ATTRIBUTE_TUPLE_SIZE, (void *) *dpp); + pgaceCreateAttributeCommon(rel, tup, pgace_attr_list); simple_heap_insert(rel, tup); -@@ -592,7 +624,8 @@ void +@@ -537,6 +560,7 @@ AddNewAttributeTuples(Oid new_rel_oid, + + tup = heap_addheader(Natts_pg_attribute, + false, ++ RelationGetDescr(rel)->tdhasseclabel, + ATTRIBUTE_TUPLE_SIZE, + (void *) *dpp); + attStruct = (Form_pg_attribute) GETSTRUCT(tup); +@@ -592,7 +616,8 @@ void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, @@ -1415,7 +1460,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { Form_pg_class rd_rel = new_rel_desc->rd_rel; Datum values[Natts_pg_class]; -@@ -642,12 +675,16 @@ InsertPgClassTuple(Relation pg_class_des +@@ -642,12 +667,16 @@ InsertPgClassTuple(Relation pg_class_des * be embarrassing to do this sort of thing in polite company. */ HeapTupleSetOid(tup, new_rel_oid); @@ -1432,7 +1477,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c heap_freetuple(tup); } -@@ -665,7 +702,8 @@ AddNewRelationTuple(Relation pg_class_de +@@ -665,7 +694,8 @@ AddNewRelationTuple(Relation pg_class_de Oid new_type_oid, Oid relowner, char relkind, @@ -1442,7 +1487,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { Form_pg_class new_rel_reltup; -@@ -725,7 +763,7 @@ AddNewRelationTuple(Relation pg_class_de +@@ -725,7 +755,7 @@ AddNewRelationTuple(Relation pg_class_de new_rel_desc->rd_att->tdtypeid = new_type_oid; /* Now build and insert the tuple */ @@ -1451,7 +1496,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c } -@@ -791,7 +829,8 @@ heap_create_with_catalog(const char *rel +@@ -791,7 +821,8 @@ heap_create_with_catalog(const char *rel int oidinhcount, OnCommitAction oncommit, Datum reloptions, @@ -1461,7 +1506,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { Relation pg_class_desc; Relation new_rel_desc; -@@ -963,13 +1002,14 @@ heap_create_with_catalog(const char *rel +@@ -963,13 +994,20 @@ heap_create_with_catalog(const char *rel new_type_oid, ownerid, relkind, @@ -1475,13 +1520,48 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind, - oidislocal, oidinhcount); + oidislocal, oidinhcount, pgace_attr_list); ++ ++ /* ++ * Fixup rel->rd_att->tdhasseclabel ++ */ ++ 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 -rpNU3 base/src/backend/catalog/index.c sepgsql/src/backend/catalog/index.c ---- base/src/backend/catalog/index.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/catalog/index.c 2008-09-25 15:22:04.000000000 +0900 -@@ -624,7 +624,7 @@ index_create(Oid heapRelationId, +--- base/src/backend/catalog/index.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/catalog/index.c 2009-02-02 11:58:34.000000000 +0900 +@@ -45,6 +45,7 @@ + #include "optimizer/clauses.h" + #include "optimizer/var.h" + #include "parser/parse_expr.h" ++#include "security/pgace.h" + #include "storage/procarray.h" + #include "storage/smgr.h" + #include "utils/builtins.h" +@@ -315,6 +316,7 @@ AppendAttributeTuples(Relation indexRela + + new_tuple = heap_addheader(Natts_pg_attribute, + false, ++ RelationGetDescr(pg_attribute)->tdhasseclabel, + ATTRIBUTE_TUPLE_SIZE, + (void *) indexTupDesc->attrs[i]); + +@@ -602,6 +604,12 @@ index_create(Oid heapRelationId, + Assert(indexRelationId == RelationGetRelid(indexRelation)); + + /* ++ * Fixup rel->rd_att->tdhasseclabel ++ */ ++ 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. +@@ -624,7 +632,7 @@ index_create(Oid heapRelationId, */ InsertPgClassTuple(pg_class, indexRelation, RelationGetRelid(indexRelation), @@ -1580,7 +1660,7 @@ diff -rpNU3 base/src/backend/catalog/pg_proc.c sepgsql/src/backend/catalog/pg_pr } diff -rpNU3 base/src/backend/catalog/toasting.c sepgsql/src/backend/catalog/toasting.c --- base/src/backend/catalog/toasting.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/catalog/toasting.c 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/catalog/toasting.c 2008-11-24 12:05:32.000000000 +0900 @@ -199,7 +199,8 @@ create_toast_table(Relation rel, Oid toa 0, ONCOMMIT_NOOP, @@ -1593,7 +1673,7 @@ diff -rpNU3 base/src/backend/catalog/toasting.c sepgsql/src/backend/catalog/toas CommandCounterIncrement(); diff -rpNU3 base/src/backend/commands/cluster.c sepgsql/src/backend/commands/cluster.c --- base/src/backend/commands/cluster.c 2008-02-03 01:11:28.000000000 +0900 -+++ sepgsql/src/backend/commands/cluster.c 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/commands/cluster.c 2008-12-28 01:06:59.000000000 +0900 @@ -666,7 +666,8 @@ make_new_heap(Oid OIDOldHeap, const char 0, ONCOMMIT_NOOP, @@ -1609,15 +1689,15 @@ diff -rpNU3 base/src/backend/commands/cluster.c sepgsql/src/backend/commands/clu HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple)); + /* Preserve SID, if any */ -+ if (HeapTupleHasSecurity(tuple)) -+ HeapTupleSetSecurity(copiedTuple, HeapTupleGetSecurity(tuple)); ++ if (HeapTupleHasSecLabel(tuple)) ++ HeapTupleSetSecLabel(copiedTuple, HeapTupleGetSecLabel(tuple)); + /* The heap rewrite module does the rest */ rewrite_heap_tuple(rwstate, tuple, copiedTuple); diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c --- base/src/backend/commands/copy.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/commands/copy.c 2008-10-01 11:19:37.000000000 +0900 ++++ sepgsql/src/backend/commands/copy.c 2008-12-28 01:06:59.000000000 +0900 @@ -22,6 +22,7 @@ #include "access/heapam.h" @@ -1639,9 +1719,9 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c int raw_buf_index; /* next byte to process */ int raw_buf_len; /* total # of bytes stored */ + -+ /* security attribute dump/restore support */ -+ FmgrInfo security_out_function; -+ bool security_force_quot; ++ /* dump/restore support for security_label */ ++ FmgrInfo seclabel_out_function; ++ bool seclabel_force_quot; } CopyStateData; typedef CopyStateData *CopyState; @@ -1650,31 +1730,11 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c static void DoCopyTo(CopyState cstate); static void CopyTo(CopyState cstate); -static void CopyOneRowTo(CopyState cstate, Oid tupleOid, -+static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid securityOid, ++static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid secLabelId, Datum *values, bool *nulls); static void CopyFrom(CopyState cstate); static bool CopyReadLine(CopyState cstate); -@@ -277,6 +283,19 @@ static bool CopyGetInt32(CopyState cstat - static void CopySendInt16(CopyState cstate, int16 val); - static bool CopyGetInt16(CopyState cstate, int16 *val); - -+/* -+ * IsWritableSecurityAttribute -+ * -+ * It returns false, if the given attribute is not -+ * a writable security system attribute. -+ */ -+#ifdef SECURITY_SYSATTR_NAME -+#define IsWritableSecurityAttribute(attnum) \ -+ ((attnum) == SecurityAttributeNumber \ -+ && pgaceSecurityAttributeNecessary()) -+#else -+#define IsWritableSecurityAttribute(attnum) (false) -+#endif - - /* - * Send copy start/stop messages for frontend copies. These have changed -@@ -1073,6 +1092,8 @@ DoCopy(const CopyStmt *stmt, const char +@@ -1073,6 +1079,8 @@ DoCopy(const CopyStmt *stmt, const char /* Generate or convert list of attributes to process */ cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist); @@ -1683,29 +1743,68 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c num_phys_attrs = tupDesc->natts; /* Convert FORCE QUOTE name list to per-column flags, check validity */ -@@ -1093,6 +1114,11 @@ DoCopy(const CopyStmt *stmt, const char +@@ -1089,11 +1097,32 @@ DoCopy(const CopyStmt *stmt, const char + 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(tupDesc->attrs[attnum - 1]->attname)))); -+ if (IsWritableSecurityAttribute(attnum)) +- NameStr(tupDesc->attrs[attnum - 1]->attname)))); +- cstate->force_quote_flags[attnum - 1] = true; ++ NameStr(attForm->attname)))); ++ } ++ ++ switch (attnum) + { -+ cstate->security_force_quot = true; -+ continue; ++ case SecurityLabelAttributeNumber: ++ cstate->seclabel_force_quot = true; ++ break; ++ ++ default: ++ cstate->force_quote_flags[attnum - 1] = true; ++ break; + } - cstate->force_quote_flags[attnum - 1] = true; } } -@@ -1115,6 +1141,9 @@ DoCopy(const CopyStmt *stmt, const char + +@@ -1111,10 +1140,24 @@ DoCopy(const CopyStmt *stmt, const char + 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(tupDesc->attrs[attnum - 1]->attname)))); -+ if (IsWritableSecurityAttribute(attnum)) +- NameStr(tupDesc->attrs[attnum - 1]->attname)))); ++ NameStr(attForm->attname)))); ++ } ++ if (SystemAttributeIsWritable(attnum)) + continue; /* ignore, if specified */ + cstate->force_notnull_flags[attnum - 1] = true; } } -@@ -1242,6 +1271,9 @@ DoCopyTo(CopyState cstate) +@@ -1242,6 +1285,9 @@ DoCopyTo(CopyState cstate) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a directory", cstate->filename))); @@ -1715,22 +1814,23 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c } PG_TRY(); -@@ -1305,16 +1337,29 @@ CopyTo(CopyState cstate) +@@ -1305,16 +1351,30 @@ CopyTo(CopyState cstate) int attnum = lfirst_int(cur); Oid out_func_oid; bool isvarlena; + FmgrInfo *out_fmgr; + Form_pg_attribute attForm; + -+ if (IsWritableSecurityAttribute(attnum)) -+ { -+ attForm = SystemAttributeDefinition(attnum, false); -+ out_fmgr = &cstate->security_out_function; -+ } -+ else ++ switch (attnum) + { ++ 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) @@ -1748,15 +1848,15 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c } /* -@@ -1369,7 +1414,14 @@ CopyTo(CopyState cstate) +@@ -1369,7 +1429,14 @@ CopyTo(CopyState cstate) CopySendChar(cstate, cstate->delim[0]); hdr_delim = true; - colname = NameStr(attr[attnum - 1]->attname); -+ if (IsWritableSecurityAttribute(attnum)) ++ if (SystemAttributeIsWritable(attnum)) + { + Form_pg_attribute attForm -+ = SystemAttributeDefinition(attnum, false); ++ = SystemAttributeDefinition(attnum, true); + colname = NameStr(attForm->attname); + } + else @@ -1764,7 +1864,7 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c CopyAttributeOutCSV(cstate, colname, false, list_length(cstate->attnumlist) == 1); -@@ -1395,11 +1447,17 @@ CopyTo(CopyState cstate) +@@ -1395,11 +1462,17 @@ CopyTo(CopyState cstate) { CHECK_FOR_INTERRUPTS(); @@ -1778,21 +1878,22 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c - CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls); + CopyOneRowTo(cstate, + HeapTupleGetOid(tuple), -+ HeapTupleGetSecurity(tuple), ++ HeapTupleGetSecLabel(tuple), + values, nulls); } heap_endscan(scandesc); -@@ -1425,7 +1483,7 @@ CopyTo(CopyState cstate) +@@ -1425,7 +1498,8 @@ CopyTo(CopyState cstate) * Emit one row during CopyTo(). */ static void -CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls) -+CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid tupleSecurity, Datum *values, bool *nulls) ++CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid secLabelId, ++ Datum *values, bool *nulls) { bool need_delim = false; FmgrInfo *out_functions = cstate->out_functions; -@@ -1464,8 +1522,10 @@ CopyOneRowTo(CopyState cstate, Oid tuple +@@ -1464,8 +1538,10 @@ CopyOneRowTo(CopyState cstate, Oid tuple foreach(cur, cstate->attnumlist) { int attnum = lfirst_int(cur); @@ -1805,30 +1906,31 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c if (!cstate->binary) { -@@ -1474,6 +1534,22 @@ CopyOneRowTo(CopyState cstate, Oid tuple +@@ -1474,6 +1550,23 @@ CopyOneRowTo(CopyState cstate, Oid tuple need_delim = true; } -+ if (IsWritableSecurityAttribute(attnum)) ++ switch (attnum) + { -+ char *tmp = pgaceSidToSecurityLabel(tupleSecurity); -+ value = CStringGetTextDatum(tmp); ++ case SecurityLabelAttributeNumber: ++ value = CStringGetTextDatum(pgaceSidToSecurityLabel(secLabelId)); + isnull = false; -+ force_quot = cstate->security_force_quot; -+ out_fmgr = &cstate->security_out_function; -+ } -+ else -+ { ++ 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) -@@ -1485,11 +1561,9 @@ CopyOneRowTo(CopyState cstate, Oid tuple +@@ -1485,11 +1578,9 @@ CopyOneRowTo(CopyState cstate, Oid tuple { if (!cstate->binary) { @@ -1842,7 +1944,7 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c list_length(cstate->attnumlist) == 1); else CopyAttributeOutText(cstate, string); -@@ -1498,8 +1572,7 @@ CopyOneRowTo(CopyState cstate, Oid tuple +@@ -1498,8 +1589,7 @@ CopyOneRowTo(CopyState cstate, Oid tuple { bytea *outputbytes; @@ -1852,21 +1954,21 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ); CopySendData(cstate, VARDATA(outputbytes), VARSIZE(outputbytes) - VARHDRSZ); -@@ -1633,10 +1706,13 @@ CopyFrom(CopyState cstate) +@@ -1633,10 +1723,13 @@ CopyFrom(CopyState cstate) num_defaults; FmgrInfo *in_functions; FmgrInfo oid_in_function; -+ FmgrInfo security_in_function; ++ FmgrInfo seclabel_in_function; Oid *typioparams; Oid oid_typioparam; -+ Oid security_typioparam; ++ Oid seclabel_typioparam; int attnum; int i; + ListCell *l; Oid in_func_oid; Datum *values; char *nulls; -@@ -1737,6 +1813,9 @@ CopyFrom(CopyState cstate) +@@ -1737,6 +1830,9 @@ CopyFrom(CopyState cstate) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a directory", cstate->filename))); @@ -1876,25 +1978,24 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c } tupDesc = RelationGetDescr(cstate->rel); -@@ -1872,6 +1951,25 @@ CopyFrom(CopyState cstate) +@@ -1872,6 +1968,24 @@ CopyFrom(CopyState cstate) fmgr_info(in_func_oid, &oid_in_function); } + foreach (l, cstate->attnumlist) + { -+ attnum = lfirst_int(l); -+ -+ if (IsWritableSecurityAttribute(attnum)) ++ switch (lfirst_int(l)) + { ++ case SecurityLabelAttributeNumber: + if (!cstate->binary) + getTypeInputInfo(TEXTOID, + &in_func_oid, -+ &security_typioparam); ++ &seclabel_typioparam); + else + getTypeBinaryInputInfo(TEXTOID, + &in_func_oid, -+ &security_typioparam); -+ fmgr_info(in_func_oid, &security_in_function); ++ &seclabel_typioparam); ++ fmgr_info(in_func_oid, &seclabel_in_function); + break; + } + } @@ -1902,22 +2003,22 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); nulls = (char *) palloc(num_phys_attrs * sizeof(char)); -@@ -1904,6 +2002,7 @@ CopyFrom(CopyState cstate) +@@ -1904,6 +2018,7 @@ CopyFrom(CopyState cstate) { bool skip_tuple; Oid loaded_oid = InvalidOid; -+ Datum loaded_security = PointerGetDatum(NULL); ++ Datum loaded_seclabel = PointerGetDatum(NULL); CHECK_FOR_INTERRUPTS(); -@@ -1978,6 +2077,32 @@ CopyFrom(CopyState cstate) +@@ -1978,6 +2093,37 @@ CopyFrom(CopyState cstate) int attnum = lfirst_int(cur); int m = attnum - 1; -+ if (IsWritableSecurityAttribute(attnum)) ++ if (SystemAttributeIsWritable(attnum)) + { + Form_pg_attribute attForm -+ = SystemAttributeDefinition(attnum, false); ++ = SystemAttributeDefinition(attnum, true); + + if (fieldno >= fldct) + ereport(ERROR, @@ -1929,11 +2030,16 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c + cstate->cur_attval = string; + if (string) + { -+ loaded_security -+ = InputFunctionCall(&security_in_function, -+ string, -+ security_typioparam, -+ attForm->atttypmod); ++ switch (attnum) ++ { ++ case SecurityLabelAttributeNumber: ++ loaded_seclabel ++ = InputFunctionCall(&seclabel_in_function, ++ string, ++ seclabel_typioparam, ++ attForm->atttypmod); ++ break; ++ } + } + cstate->cur_attname = NULL; + cstate->cur_attval = NULL; @@ -1943,11 +2049,11 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c if (fieldno >= fldct) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), -@@ -2048,6 +2173,27 @@ CopyFrom(CopyState cstate) +@@ -2048,6 +2194,31 @@ CopyFrom(CopyState cstate) int attnum = lfirst_int(cur); int m = attnum - 1; -+ if (IsWritableSecurityAttribute(attnum)) ++ if (SystemAttributeIsWritable(attnum)) + { + Form_pg_attribute attForm + = SystemAttributeDefinition(attnum, false); @@ -1956,14 +2062,18 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c + cstate->cur_attname = NameStr(attForm->attname); + i++; + -+ tmp = CopyReadBinaryAttribute(cstate, -+ i, -+ &security_in_function, -+ security_typioparam, -+ attForm->atttypmod, -+ &isnull); -+ if (!isnull) -+ loaded_security = tmp; ++ switch (attnum) ++ { ++ 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; + } @@ -1971,20 +2081,19 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c cstate->cur_attname = NameStr(attr[m]->attname); i++; values[m] = CopyReadBinaryAttribute(cstate, -@@ -2079,6 +2225,12 @@ CopyFrom(CopyState cstate) +@@ -2079,6 +2250,11 @@ CopyFrom(CopyState cstate) if (cstate->oids && file_has_oids) HeapTupleSetOid(tuple, loaded_oid); -+ if (loaded_security != PointerGetDatum(NULL)) ++ if (loaded_seclabel != PointerGetDatum(NULL)) + { -+ Oid security_id -+ = pgaceSecurityLabelToSid(TextDatumGetCString(loaded_security)); -+ HeapTupleSetSecurity(tuple, security_id); ++ char *label = TextDatumGetCString(loaded_seclabel); ++ HeapTupleSetSecLabel(tuple, pgaceSecurityLabelToSid(label)); + } /* Triggers and stuff need to be invoked in query context. */ MemoryContextSwitchTo(oldcontext); -@@ -2102,6 +2254,9 @@ CopyFrom(CopyState cstate) +@@ -2102,6 +2278,9 @@ CopyFrom(CopyState cstate) } } @@ -1994,7 +2103,7 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c if (!skip_tuple) { /* Place tuple in tuple slot */ -@@ -3364,6 +3519,18 @@ CopyGetAttnums(TupleDesc tupDesc, Relati +@@ -3364,6 +3543,16 @@ CopyGetAttnums(TupleDesc tupDesc, Relati break; } } @@ -2002,18 +2111,16 @@ diff -rpNU3 base/src/backend/commands/copy.c sepgsql/src/backend/commands/copy.c + /* Is it writable system column? */ + if (attnum == InvalidAttrNumber) + { -+ Form_pg_attribute attForm; -+ bool relhasoids = RelationGetForm(rel)->relhasoids; -+ -+ attForm = SystemAttributeByName(name, relhasoids); -+ if (attForm && IsWritableSecurityAttribute(attForm->attnum)) ++ Form_pg_attribute attForm ++ = SystemAttributeByName(name, tupDesc->tdhasoid); ++ if (attForm && SystemAttributeIsWritable(attForm->attnum)) + attnum = attForm->attnum; + } + if (attnum == InvalidAttrNumber) { if (rel != NULL) -@@ -3413,7 +3580,9 @@ copy_dest_receive(TupleTableSlot *slot, +@@ -3413,7 +3602,9 @@ copy_dest_receive(TupleTableSlot *slot, slot_getallattrs(slot); /* And send the data */ @@ -2210,26 +2317,6 @@ diff -rpNU3 base/src/backend/commands/lockcmds.c sepgsql/src/backend/commands/lo if (lockstmt->nowait) rel = relation_open_nowait(reloid, lockstmt->mode); else -diff -rpNU3 base/src/backend/commands/prepare.c sepgsql/src/backend/commands/prepare.c ---- base/src/backend/commands/prepare.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql/src/backend/commands/prepare.c 2008-06-14 02:36:58.000000000 +0900 -@@ -27,6 +27,7 @@ - #include "parser/parse_expr.h" - #include "parser/parse_type.h" - #include "rewrite/rewriteHandler.h" -+#include "security/pgace.h" - #include "tcop/pquery.h" - #include "tcop/tcopprot.h" - #include "tcop/utility.h" -@@ -359,6 +360,8 @@ EvaluateParams(PreparedStatement *pstmt, - lfirst(l) = expr; - i++; - } -+ /* Evaluate permissions to use parameters */ -+ pgaceEvaluateParams(params); - - /* Prepare the expressions for execution */ - exprstates = (List *) ExecPrepareExpr((Expr *) params, estate); diff -rpNU3 base/src/backend/commands/proclang.c sepgsql/src/backend/commands/proclang.c --- base/src/backend/commands/proclang.c 2008-06-12 22:34:19.000000000 +0900 +++ sepgsql/src/backend/commands/proclang.c 2008-06-14 02:36:58.000000000 +0900 @@ -2255,7 +2342,7 @@ diff -rpNU3 base/src/backend/commands/proclang.c sepgsql/src/backend/commands/pr else diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/tablecmds.c --- base/src/backend/commands/tablecmds.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql/src/backend/commands/tablecmds.c 2008-11-05 10:01:30.000000000 +0900 ++++ sepgsql/src/backend/commands/tablecmds.c 2009-01-21 17:26:07.000000000 +0900 @@ -57,6 +57,7 @@ #include "parser/parser.h" #include "rewrite/rewriteDefine.h" @@ -2274,7 +2361,16 @@ diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/t StoreCatalogInheritance(relationId, inheritOids); -@@ -2031,6 +2033,7 @@ ATPrepCmd(List **wqueue, Relation rel, A +@@ -598,6 +600,8 @@ ExecuteTruncate(TruncateStmt *stmt) + heap_truncate_check_FKs(rels, false); + #endif + ++ pgaceExecTruncate(rels); ++ + /* + * OK, truncate each table. + */ +@@ -2031,6 +2035,7 @@ ATPrepCmd(List **wqueue, Relation rel, A case AT_DisableRule: case AT_AddInherit: /* INHERIT / NO INHERIT */ case AT_DropInherit: @@ -2282,7 +2378,7 @@ diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/t ATSimplePermissions(rel, false); /* These commands never recurse */ /* No command-specific prep needed */ -@@ -2253,6 +2256,9 @@ ATExecCmd(AlteredTableInfo *tab, Relatio +@@ -2253,6 +2258,9 @@ ATExecCmd(AlteredTableInfo *tab, Relatio case AT_DropInherit: ATExecDropInherit(rel, (RangeVar *) cmd->def); break; @@ -2292,7 +2388,7 @@ diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/t default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); -@@ -2591,11 +2597,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oi +@@ -2591,11 +2599,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oi if (newrel) { Oid tupOid = InvalidOid; @@ -2302,24 +2398,32 @@ diff -rpNU3 base/src/backend/commands/tablecmds.c sepgsql/src/backend/commands/t heap_deform_tuple(tuple, oldTupDesc, values, isnull); if (oldTupDesc->tdhasoid) tupOid = HeapTupleGetOid(tuple); -+ if (HeapTupleHasSecurity(tuple)) -+ tupSid = HeapTupleGetSecurity(tuple); ++ if (HeapTupleHasSecLabel(tuple)) ++ tupSid = HeapTupleGetSecLabel(tuple); /* Set dropped attributes to null in new tuple */ foreach(lc, dropped_attrs) -@@ -2627,6 +2636,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oi +@@ -2627,6 +2638,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oi /* Preserve OID, if any */ if (newTupDesc->tdhasoid) HeapTupleSetOid(tuple, tupOid); + /* Preserve Security ID, if any */ + if (tupSid != InvalidOid) -+ HeapTupleSetSecurity(tuple, tupSid); ++ HeapTupleSetSecLabel(tuple, tupSid); } /* Now check any constraints on the possibly-changed tuple */ +@@ -3113,6 +3127,7 @@ ATExecAddColumn(AlteredTableInfo *tab, R + + attributeTuple = heap_addheader(Natts_pg_attribute, + false, ++ RelationGetDescr(attrdesc)->tdhasseclabel, + ATTRIBUTE_TUPLE_SIZE, + (void *) &attributeD); + diff -rpNU3 base/src/backend/commands/trigger.c sepgsql/src/backend/commands/trigger.c ---- base/src/backend/commands/trigger.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql/src/backend/commands/trigger.c 2008-11-05 10:01:30.000000000 +0900 +--- base/src/backend/commands/trigger.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/commands/trigger.c 2009-02-02 11:58:34.000000000 +0900 @@ -31,6 +31,7 @@ #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -2328,22 +2432,77 @@ diff -rpNU3 base/src/backend/commands/trigger.c sepgsql/src/backend/commands/tri #include "tcop/utility.h" #include "utils/acl.h" #include "utils/builtins.h" -@@ -1574,6 +1575,12 @@ ExecCallTriggerFunc(TriggerData *trigdat +@@ -1551,10 +1552,16 @@ ExecCallTriggerFunc(TriggerData *trigdat + * 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. + */ +@@ -1574,6 +1581,7 @@ ExecCallTriggerFunc(TriggerData *trigdat */ InitFunctionCallInfoData(fcinfo, finfo, 0, (Node *) trigdata, NULL); -+ if (!pgaceCallFunctionTrigger(finfo, trigdata)) -+ { -+ MemoryContextSwitchTo(oldContext); -+ return (HeapTuple) DatumGetPointer(NULL); -+ } + result = FunctionCallInvoke(&fcinfo); MemoryContextSwitchTo(oldContext); +@@ -1971,6 +1979,20 @@ ExecBRUpdateTriggers(EState *estate, Res + 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 (HeapTupleHasSecLabel(newtuple) && ++ !OidIsValid(HeapTupleGetSecLabel(newtuple))) ++ HeapTupleSetSecLabel(newtuple, HeapTupleGetSecLabel(trigtuple)); ++ + LocTriggerData.type = T_TriggerData; + LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | + TRIGGER_EVENT_ROW | +diff -rpNU3 base/src/backend/executor/execJunk.c sepgsql/src/backend/executor/execJunk.c +--- base/src/backend/executor/execJunk.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/executor/execJunk.c 2008-11-21 23:11:55.000000000 +0900 +@@ -60,7 +60,8 @@ + * An optional resultSlot can be passed as well. + */ + JunkFilter * +-ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot) ++ExecInitJunkFilter(List *targetList, bool hasoid, bool hassecurity, ++ TupleTableSlot *slot) + { + JunkFilter *junkfilter; + TupleDesc cleanTupType; +@@ -72,7 +73,7 @@ ExecInitJunkFilter(List *targetList, boo + /* + * Compute the tuple descriptor for the cleaned tuple. + */ +- cleanTupType = ExecCleanTypeFromTL(targetList, hasoid); ++ cleanTupType = ExecCleanTypeFromTL(targetList, hasoid, hassecurity); + + /* + * Use the given slot, or make a new slot if we weren't given one. diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/execMain.c --- base/src/backend/executor/execMain.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/executor/execMain.c 2008-10-15 10:00:50.000000000 +0900 ++++ sepgsql/src/backend/executor/execMain.c 2008-12-28 01:06:59.000000000 +0900 @@ -49,6 +49,7 @@ #include "parser/parse_clause.h" #include "parser/parse_expr.h" @@ -2361,7 +2520,90 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex /* * If the transaction is read-only, we need to check if any writes are * planned to non-temporary tables. EXPLAIN is considered read-only. -@@ -1251,6 +1254,54 @@ ExecEndPlan(PlanState *planstate, EState +@@ -738,16 +741,16 @@ InitPlan(QueryDesc *queryDesc, int eflag + for (i = 0; i < as_nplans; i++) + { + PlanState *subplan = appendplans[i]; ++ Relation resultRel = resultRelInfo->ri_RelationDesc; + JunkFilter *j; + + if (operation == CMD_UPDATE) +- ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc, +- subplan->plan->targetlist); ++ ExecCheckPlanOutput(resultRel, subplan->plan->targetlist); + + j = ExecInitJunkFilter(subplan->plan->targetlist, +- resultRelInfo->ri_RelationDesc->rd_att->tdhasoid, +- ExecAllocTableSlot(estate->es_tupleTable)); +- ++ RelationGetDescr(resultRel)->tdhasoid, ++ 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 +@@ -789,7 +792,7 @@ InitPlan(QueryDesc *queryDesc, int eflag + planstate->plan->targetlist); + + j = ExecInitJunkFilter(planstate->plan->targetlist, +- tupType->tdhasoid, ++ tupType->tdhasoid, tupType->tdhasseclabel, + ExecAllocTableSlot(estate->es_tupleTable)); + estate->es_junkFilter = j; + if (estate->es_result_relation_info) +@@ -848,7 +851,7 @@ InitPlan(QueryDesc *queryDesc, int eflag + * 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); +@@ -1171,6 +1174,42 @@ ExecContextForcesOids(PlanState *plansta + return false; + } + ++/* ++ * ExecContextForcesSecLabel ++ * ++ * We need to ensure that result tuples have space for security attribute, ++ * if the security mechanism are going to be stored it into the given ++ * relation. ++ * The hook gives relation identifier and its kind as a hint. However, ++ * the relation identifer can be InvalidOid when the relation is to ++ * be newly created via SELECT INTO, because the creation of the relation ++ * will be done after invocation of the function. ++ */ ++bool ExecContextForcesSecLabel(PlanState *planstate, bool *hasseclabel) ++{ ++ if (planstate->state->es_select_into) ++ { ++ IntoClause *into = planstate->state->es_plannedstmt->intoClause; ++ ++ Assert(into != NULL); ++ ++ *hasseclabel = pgaceTupleDescHasSecLabel(NULL, into->options); ++ return true; ++ } ++ else ++ { ++ ResultRelInfo *ri = planstate->state->es_result_relation_info; ++ ++ if (ri && ri->ri_RelationDesc) ++ { ++ *hasseclabel = pgaceTupleDescHasSecLabel(ri->ri_RelationDesc, NIL); ++ return true; ++ } ++ } ++ ++ return false; ++} ++ + /* ---------------------------------------------------------------- + * ExecEndPlan + * +@@ -1251,6 +1290,61 @@ ExecEndPlan(PlanState *planstate, EState } } @@ -2374,14 +2616,14 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex + */ +static void +fetchWritableSystemAttribute(JunkFilter *junkfilter, TupleTableSlot *slot, -+ Datum *tts_security) ++ Datum *tts_seclabel) +{ + AttrNumber attno; + Datum datum; + bool isnull; + -+#ifdef SECURITY_SYSATTR_NAME -+ attno = ExecFindJunkAttribute(junkfilter, SECURITY_SYSATTR_NAME); ++ /* for Security Label */ ++ attno = ExecFindJunkAttribute(junkfilter, SecurityLabelAttributeName); + if (attno != InvalidAttrNumber) + { + datum = ExecGetJunkAttribute(slot, attno, &isnull); @@ -2389,63 +2631,70 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex + ereport(ERROR, + (errcode(ERRCODE_PGACE_ERROR), + errmsg("null value in column \"%s\" violates not-null constraint", -+ SECURITY_SYSATTR_NAME))); -+ *tts_security = datum; ++ SecurityLabelAttributeName))); ++ *tts_seclabel = datum; + } -+#endif +} + +static void +storeWritableSystemAttribute(Relation rel, TupleTableSlot *slot, HeapTuple tuple) +{ + /* for security attribute */ -+ if (HeapTupleHasSecurity(tuple)) ++ if (HeapTupleHasSecLabel(tuple)) + { -+ if (!DatumGetPointer(slot->tts_security)) -+ HeapTupleSetSecurity(tuple, InvalidOid); ++ if (!DatumGetPointer(slot->tts_seclabel)) ++ HeapTupleSetSecLabel(tuple, InvalidOid); + else + { -+ char *label = TextDatumGetCString(slot->tts_security); ++ char *label = TextDatumGetCString(slot->tts_seclabel); + -+ HeapTupleSetSecurity(tuple, ++ HeapTupleSetSecLabel(tuple, + pgaceSecurityLabelToSid(label)); + } + } ++ else if (DatumGetPointer(slot->tts_seclabel)) ++ { ++ ereport(ERROR, ++ (errcode(ERRCODE_PGACE_ERROR), ++ errmsg("enhanced security mechanism does not allocate " ++ "a field to store security attribute for relation: %s", ++ RelationGetRelationName(rel)))); ++ } +} + /* ---------------------------------------------------------------- * ExecutePlan * -@@ -1318,6 +1369,8 @@ ExecutePlan(EState *estate, +@@ -1318,6 +1412,8 @@ ExecutePlan(EState *estate, for (;;) { -+ Datum tts_security = PointerGetDatum(NULL); ++ Datum tts_seclabel = PointerGetDatum(NULL); + /* Reset the per-output-tuple exprcontext */ ResetPerTupleExprContext(estate); -@@ -1442,6 +1495,11 @@ lnext: ; +@@ -1442,6 +1538,11 @@ lnext: ; } /* + * extract writable system attribute + */ -+ fetchWritableSystemAttribute(junkfilter, slot, &tts_security); ++ fetchWritableSystemAttribute(junkfilter, slot, &tts_seclabel); + + /* * extract the 'ctid' junk attribute. */ if (operation == CMD_UPDATE || operation == CMD_DELETE) -@@ -1468,6 +1526,7 @@ lnext: ; +@@ -1468,6 +1569,7 @@ lnext: ; if (operation != CMD_DELETE) slot = ExecFilterJunk(junkfilter, slot); } -+ slot->tts_security = tts_security; ++ slot->tts_seclabel = tts_seclabel; /* * now that we have a tuple, do the appropriate thing with it.. either -@@ -1588,6 +1647,8 @@ ExecInsert(TupleTableSlot *slot, +@@ -1588,6 +1690,8 @@ ExecInsert(TupleTableSlot *slot, resultRelInfo = estate->es_result_relation_info; resultRelationDesc = resultRelInfo->ri_RelationDesc; @@ -2454,7 +2703,7 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex /* BEFORE ROW INSERT Triggers */ if (resultRelInfo->ri_TrigDesc && resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) -@@ -1624,6 +1685,13 @@ ExecInsert(TupleTableSlot *slot, +@@ -1624,6 +1728,13 @@ ExecInsert(TupleTableSlot *slot, ExecConstraints(resultRelInfo, slot, estate); /* @@ -2468,7 +2717,7 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex * insert the tuple * * Note: heap_insert returns the tid (location) of the new tuple in the -@@ -1690,6 +1758,10 @@ ExecDelete(ItemPointer tupleid, +@@ -1690,6 +1801,10 @@ ExecDelete(ItemPointer tupleid, return; } @@ -2479,7 +2728,7 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex /* * delete the tuple * -@@ -1826,6 +1898,8 @@ ExecUpdate(TupleTableSlot *slot, +@@ -1826,6 +1941,8 @@ ExecUpdate(TupleTableSlot *slot, resultRelInfo = estate->es_result_relation_info; resultRelationDesc = resultRelInfo->ri_RelationDesc; @@ -2488,7 +2737,7 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex /* BEFORE ROW UPDATE Triggers */ if (resultRelInfo->ri_TrigDesc && resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0) -@@ -1870,6 +1944,13 @@ lreplace:; +@@ -1870,6 +1987,13 @@ lreplace:; ExecConstraints(resultRelInfo, slot, estate); /* @@ -2502,7 +2751,7 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex * replace the heap tuple * * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that -@@ -2733,7 +2814,8 @@ OpenIntoRel(QueryDesc *queryDesc) +@@ -2733,7 +2857,8 @@ OpenIntoRel(QueryDesc *queryDesc) 0, into->onCommit, reloptions, @@ -2512,7 +2761,7 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex FreeTupleDesc(tupdesc); -@@ -2839,6 +2921,12 @@ intorel_receive(TupleTableSlot *slot, De +@@ -2839,6 +2964,12 @@ intorel_receive(TupleTableSlot *slot, De tuple = ExecCopySlotTuple(slot); @@ -2526,8 +2775,8 @@ diff -rpNU3 base/src/backend/executor/execMain.c sepgsql/src/backend/executor/ex tuple, estate->es_output_cid, diff -rpNU3 base/src/backend/executor/execQual.c sepgsql/src/backend/executor/execQual.c ---- base/src/backend/executor/execQual.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/executor/execQual.c 2008-08-15 11:22:38.000000000 +0900 +--- base/src/backend/executor/execQual.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/executor/execQual.c 2009-02-02 11:58:34.000000000 +0900 @@ -47,6 +47,7 @@ #include "nodes/makefuncs.h" #include "optimizer/planmain.h" @@ -2536,19 +2785,26 @@ diff -rpNU3 base/src/backend/executor/execQual.c sepgsql/src/backend/executor/ex #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" -@@ -1015,6 +1016,9 @@ init_fcache(Oid foid, FuncExprState *fca - fcache->setArgsValid = false; - fcache->shutdown_reg = false; - fcache->func.fn_expr = (Node *) fcache->xprstate.expr; -+ -+ /* Check permission to call function by security subsystem */ -+ pgaceCallFunction(&fcache->func); - } +@@ -1010,6 +1011,7 @@ init_fcache(Oid foid, FuncExprState *fca - /* + /* Set up the primary fmgr lookup information */ + fmgr_info_cxt(foid, &(fcache->func), fcacheCxt); ++ pgaceCallFunction(&fcache->func); + + /* Initialize additional info */ + fcache->setArgsValid = false; +@@ -3679,6 +3681,8 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprS + + /* Initialize additional info */ + astate->elemfunc.fn_expr = (Node *) acoerce; ++ ++ pgaceCallFunction(&astate->elemfunc); + } + + /* diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/execScan.c --- base/src/backend/executor/execScan.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/executor/execScan.c 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/executor/execScan.c 2008-12-28 01:06:59.000000000 +0900 @@ -20,6 +20,7 @@ #include "executor/executor.h" @@ -2611,15 +2867,206 @@ diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/ex { /* * Found a satisfactory scan tuple. +@@ -197,6 +215,7 @@ tlist_matches_tupdesc(PlanState *ps, Lis + int numattrs = tupdesc->natts; + int attrno; + bool hasoid; ++ bool hasseclabel; + ListCell *tlist_item = list_head(tlist); + + /* Check the tlist attributes */ +@@ -240,12 +259,16 @@ tlist_matches_tupdesc(PlanState *ps, Lis + return false; /* tlist too long */ + + /* +- * If the plan context requires a particular hasoid setting, then that has +- * to match, too. ++ * 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 (ExecContextForcesSecLabel(ps, &hasseclabel) && ++ hasseclabel != tupdesc->tdhasseclabel) ++ return false; ++ + return true; + } +diff -rpNU3 base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/execTuples.c +--- base/src/backend/executor/execTuples.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/executor/execTuples.c 2008-12-28 01:06:59.000000000 +0900 +@@ -100,7 +100,7 @@ + + + static TupleDesc ExecTypeFromTLInternal(List *targetList, +- bool hasoid, bool skipjunk); ++ bool hasoid, bool hassecurity, bool skipjunk); + + + /* ---------------------------------------------------------------- +@@ -921,9 +921,9 @@ ExecInitNullTupleSlot(EState *estate, Tu + * ---------------------------------------------------------------- + */ + TupleDesc +-ExecTypeFromTL(List *targetList, bool hasoid) ++ExecTypeFromTL(List *targetList, bool hasoid, bool hasseclabel) + { +- return ExecTypeFromTLInternal(targetList, hasoid, false); ++ return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, false); + } + + /* ---------------------------------------------------------------- +@@ -933,13 +933,14 @@ ExecTypeFromTL(List *targetList, bool ha + * ---------------------------------------------------------------- + */ + TupleDesc +-ExecCleanTypeFromTL(List *targetList, bool hasoid) ++ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel) + { +- return ExecTypeFromTLInternal(targetList, hasoid, true); ++ return ExecTypeFromTLInternal(targetList, hasoid, hasseclabel, true); + } + + static TupleDesc +-ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk) ++ExecTypeFromTLInternal(List *targetList, ++ bool hasoid, bool hasseclabel, bool skipjunk) + { + TupleDesc typeInfo; + ListCell *l; +@@ -951,6 +952,7 @@ ExecTypeFromTLInternal(List *targetList, + else + len = ExecTargetListLength(targetList); + typeInfo = CreateTemplateTupleDesc(len, hasoid); ++ typeInfo->tdhasseclabel = hasseclabel; + + foreach(l, targetList) + { +diff -rpNU3 base/src/backend/executor/execUtils.c sepgsql/src/backend/executor/execUtils.c +--- base/src/backend/executor/execUtils.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/executor/execUtils.c 2008-12-28 01:06:59.000000000 +0900 +@@ -506,6 +506,7 @@ void + ExecAssignResultTypeFromTL(PlanState *planstate) + { + bool hasoid; ++ bool hassecurity; + TupleDesc tupDesc; + + if (ExecContextForcesOids(planstate, &hasoid)) +@@ -518,12 +519,15 @@ ExecAssignResultTypeFromTL(PlanState *pl + hasoid = false; + } + ++ if (!ExecContextForcesSecLabel(planstate, &hassecurity)) ++ hassecurity = 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); ++ tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid, hassecurity); + ExecAssignResultType(planstate, tupDesc); + } + +diff -rpNU3 base/src/backend/executor/functions.c sepgsql/src/backend/executor/functions.c +--- base/src/backend/executor/functions.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/executor/functions.c 2008-11-21 23:11:55.000000000 +0900 +@@ -995,7 +995,7 @@ check_sql_fn_retval(Oid func_id, Oid ret + * what the caller expects will happen at runtime. + */ + if (junkFilter) +- *junkFilter = ExecInitJunkFilter(tlist, false, NULL); ++ *junkFilter = ExecInitJunkFilter(tlist, false, false, NULL); + return true; + } + Assert(tupdesc); +diff -rpNU3 base/src/backend/executor/nodeAgg.c sepgsql/src/backend/executor/nodeAgg.c +--- base/src/backend/executor/nodeAgg.c 2008-11-05 09:57:00.000000000 +0900 ++++ sepgsql/src/backend/executor/nodeAgg.c 2009-01-16 17:07:29.000000000 +0900 +@@ -80,6 +80,7 @@ + #include "parser/parse_coerce.h" + #include "parser/parse_expr.h" + #include "parser/parse_oper.h" ++#include "security/pgace.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/lsyscache.h" +@@ -1398,6 +1399,8 @@ ExecInitAgg(Agg *node, EState *estate, i + 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; + +@@ -1461,11 +1464,13 @@ ExecInitAgg(Agg *node, EState *estate, i + + 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 -rpNU3 base/src/backend/executor/nodeMergejoin.c sepgsql/src/backend/executor/nodeMergejoin.c +--- base/src/backend/executor/nodeMergejoin.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/executor/nodeMergejoin.c 2009-01-16 17:07:29.000000000 +0900 +@@ -98,6 +98,7 @@ + #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" +@@ -221,6 +222,7 @@ MJExamineQuals(List *mergeclauses, + + /* Set up the fmgr lookup information */ + fmgr_info(cmpproc, &(clause->cmpfinfo)); ++ pgaceCallFunction(&clause->cmpfinfo); + + /* Fill the additional comparison-strategy flags */ + if (opstrategy == BTLessStrategyNumber) +diff -rpNU3 base/src/backend/executor/nodeSubplan.c sepgsql/src/backend/executor/nodeSubplan.c +--- base/src/backend/executor/nodeSubplan.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/executor/nodeSubplan.c 2008-11-21 23:11:55.000000000 +0900 +@@ -855,7 +855,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanSt + * (hack alert!). The righthand expressions will be evaluated in our + * own innerecontext. + */ +- tupDesc = ExecTypeFromTL(leftptlist, false); ++ tupDesc = ExecTypeFromTL(leftptlist, false, false); + slot = ExecAllocTableSlot(tupTable); + ExecSetSlotDescriptor(slot, tupDesc); + sstate->projLeft = ExecBuildProjectionInfo(lefttlist, +@@ -863,7 +863,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanSt + slot, + NULL); + +- tupDesc = ExecTypeFromTL(rightptlist, false); ++ tupDesc = ExecTypeFromTL(rightptlist, false, false); + slot = ExecAllocTableSlot(tupTable); + ExecSetSlotDescriptor(slot, tupDesc); + sstate->projRight = ExecBuildProjectionInfo(righttlist, diff -rpNU3 base/src/backend/executor/spi.c sepgsql/src/backend/executor/spi.c ---- base/src/backend/executor/spi.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql/src/backend/executor/spi.c 2008-11-05 10:01:30.000000000 +0900 -@@ -606,6 +606,8 @@ SPI_modifytuple(Relation rel, HeapTuple +--- base/src/backend/executor/spi.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/executor/spi.c 2009-02-02 11:58:34.000000000 +0900 +@@ -631,6 +631,8 @@ SPI_modifytuple(Relation rel, HeapTuple mtuple->t_tableOid = tuple->t_tableOid; if (rel->rd_att->tdhasoid) HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple)); -+ if (HeapTupleHasSecurity(tuple)) -+ HeapTupleSetSecurity(mtuple, HeapTupleGetSecurity(tuple)); ++ if (HeapTupleHasSecLabel(tuple)) ++ HeapTupleSetSecLabel(mtuple, HeapTupleGetSecLabel(tuple)); } else { @@ -2686,7 +3133,7 @@ diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fss PG_RETURN_INT32(0); diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c --- base/src/backend/nodes/copyfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/nodes/copyfuncs.c 2008-09-22 15:02:01.000000000 +0900 ++++ sepgsql/src/backend/nodes/copyfuncs.c 2009-01-21 17:02:57.000000000 +0900 @@ -24,6 +24,7 @@ #include "nodes/plannodes.h" @@ -2743,7 +3190,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun return newnode; } -@@ -2998,6 +3005,49 @@ _copyValue(Value *from) +@@ -2998,6 +3005,26 @@ _copyValue(Value *from) return newnode; } @@ -2751,41 +3198,18 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun + * nodes/security.h copy functions + * **************************************************************** + */ -+static SEvalItemRelation * -+_copySEvalItemRelation(SEvalItemRelation *from) ++static SelinuxEvalItem * ++_copySelinuxEvalItem(SelinuxEvalItem *from) +{ -+ SEvalItemRelation *newnode = makeNode(SEvalItemRelation); -+ -+ COPY_SCALAR_FIELD(perms); ++ SelinuxEvalItem *newnode = makeNode(SelinuxEvalItem); ++ int n; + + COPY_SCALAR_FIELD(relid); + COPY_SCALAR_FIELD(inh); + -+ return newnode; -+} -+ -+static SEvalItemAttribute * -+_copySEvalItemAttribute(SEvalItemAttribute *from) -+{ -+ SEvalItemAttribute *newnode = makeNode(SEvalItemAttribute); -+ -+ COPY_SCALAR_FIELD(perms); -+ -+ COPY_SCALAR_FIELD(relid); -+ COPY_SCALAR_FIELD(inh); -+ COPY_SCALAR_FIELD(attno); -+ -+ return newnode; -+} -+ -+static SEvalItemProcedure * -+_copySEvalItemProcedure(SEvalItemProcedure *from) -+{ -+ SEvalItemProcedure *newnode = makeNode(SEvalItemProcedure); -+ -+ COPY_SCALAR_FIELD(perms); -+ -+ COPY_SCALAR_FIELD(funcid); ++ COPY_SCALAR_FIELD(relperms); ++ COPY_SCALAR_FIELD(nattrs); ++ COPY_POINTER_FIELD(attperms, from->nattrs * sizeof(uint32)); + + return newnode; +} @@ -2793,25 +3217,19 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun /* * copyObject * -@@ -3600,6 +3650,15 @@ copyObject(void *from) +@@ -3600,6 +3627,9 @@ copyObject(void *from) case T_XmlSerialize: retval = _copyXmlSerialize(from); break; -+ case T_SEvalItemRelation: -+ retval = _copySEvalItemRelation(from); -+ break; -+ case T_SEvalItemAttribute: -+ retval = _copySEvalItemAttribute(from); -+ break; -+ case T_SEvalItemProcedure: -+ retval = _copySEvalItemProcedure(from); ++ case T_SelinuxEvalItem: ++ retval = _copySelinuxEvalItem(from); + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from)); diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalfuncs.c --- base/src/backend/nodes/equalfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/nodes/equalfuncs.c 2008-09-22 16:53:15.000000000 +0900 ++++ sepgsql/src/backend/nodes/equalfuncs.c 2009-01-21 17:02:57.000000000 +0900 @@ -26,6 +26,7 @@ #include "postgres.h" @@ -2844,38 +3262,20 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf return true; } -@@ -1925,6 +1929,39 @@ _equalXmlSerialize(XmlSerialize *a, XmlS +@@ -1925,6 +1929,21 @@ _equalXmlSerialize(XmlSerialize *a, XmlS } /* + * Stuff from nodes/security.h + */ +static bool -+_equalSEvalItemRelation(SEvalItemRelation *a, SEvalItemRelation *b) ++_equalSelinuxEvalItem(SelinuxEvalItem *a, SelinuxEvalItem *b) +{ -+ COMPARE_SCALAR_FIELD(perms); + COMPARE_SCALAR_FIELD(relid); + COMPARE_SCALAR_FIELD(inh); -+ -+ return true; -+} -+ -+static bool -+_equalSEvalItemAttribute(SEvalItemAttribute *a, SEvalItemAttribute *b) -+{ -+ COMPARE_SCALAR_FIELD(perms); -+ COMPARE_SCALAR_FIELD(relid); -+ COMPARE_SCALAR_FIELD(inh); -+ COMPARE_SCALAR_FIELD(attno); -+ -+ return true; -+} -+ -+static bool -+_equalSEvalItemProcedure(SEvalItemProcedure *a, SEvalItemProcedure *b) -+{ -+ COMPARE_SCALAR_FIELD(perms); -+ COMPARE_SCALAR_FIELD(funcid); ++ COMPARE_SCALAR_FIELD(relperms); ++ COMPARE_SCALAR_FIELD(nattrs); ++ COMPARE_POINTER_FIELD(attperms, a->nattrs * sizeof(uint32)); + + return true; +} @@ -2884,25 +3284,19 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf * Stuff from pg_list.h */ -@@ -2527,6 +2564,15 @@ equal(void *a, void *b) +@@ -2527,6 +2546,9 @@ equal(void *a, void *b) case T_XmlSerialize: retval = _equalXmlSerialize(a, b); break; -+ case T_SEvalItemRelation: -+ retval = _equalSEvalItemRelation(a, b); -+ break; -+ case T_SEvalItemAttribute: -+ retval = _equalSEvalItemAttribute(a, b); -+ break; -+ case T_SEvalItemProcedure: -+ retval = _equalSEvalItemProcedure(a, b); ++ case T_SelinuxEvalItem: ++ retval = _equalSelinuxEvalItem(a, b); + break; default: elog(ERROR, "unrecognized node type: %d", diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c ---- base/src/backend/nodes/outfuncs.c 2008-01-14 22:59:48.000000000 +0900 -+++ sepgsql/src/backend/nodes/outfuncs.c 2008-09-22 16:53:15.000000000 +0900 +--- base/src/backend/nodes/outfuncs.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/nodes/outfuncs.c 2009-02-02 11:58:34.000000000 +0900 @@ -26,6 +26,7 @@ #include "lib/stringinfo.h" #include "nodes/plannodes.h" @@ -2935,7 +3329,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1544,6 +1548,7 @@ _outCreateStmt(StringInfo str, CreateStm +@@ -1545,6 +1549,7 @@ _outCreateStmt(StringInfo str, CreateStm WRITE_NODE_FIELD(options); WRITE_ENUM_FIELD(oncommit, OnCommitAction); WRITE_STRING_FIELD(tablespacename); @@ -2943,7 +3337,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1659,6 +1664,7 @@ _outColumnDef(StringInfo str, ColumnDef +@@ -1660,6 +1665,7 @@ _outColumnDef(StringInfo str, ColumnDef WRITE_NODE_FIELD(raw_default); WRITE_STRING_FIELD(cooked_default); WRITE_NODE_FIELD(constraints); @@ -2951,7 +3345,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1748,6 +1754,7 @@ _outQuery(StringInfo str, Query *node) +@@ -1749,6 +1755,7 @@ _outQuery(StringInfo str, Query *node) WRITE_NODE_FIELD(limitCount); WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(setOperations); @@ -2959,7 +3353,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1833,6 +1840,7 @@ _outRangeTblEntry(StringInfo str, RangeT +@@ -1834,6 +1841,7 @@ _outRangeTblEntry(StringInfo str, RangeT WRITE_BOOL_FIELD(inFromCl); WRITE_UINT_FIELD(requiredPerms); WRITE_OID_FIELD(checkAsUser); @@ -2967,7 +3361,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -2045,6 +2053,43 @@ _outFkConstraint(StringInfo str, FkConst +@@ -2046,6 +2054,29 @@ _outFkConstraint(StringInfo str, FkConst WRITE_BOOL_FIELD(skip_validation); } @@ -2977,59 +3371,39 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs + * + *****************************************************************************/ +static void -+_outSEvalItemRelation(StringInfo str, SEvalItemRelation *node) ++_outSelinuxEvalItem(StringInfo str, SelinuxEvalItem *node) +{ -+ WRITE_NODE_TYPE("SEVALITEMRELATION"); ++ int i; + -+ WRITE_UINT_FIELD(perms); ++ WRITE_NODE_TYPE("SELINUXEVALITEM"); + + WRITE_OID_FIELD(relid); + WRITE_BOOL_FIELD(inh); -+} + -+static void -+_outSEvalItemAttribute(StringInfo str, SEvalItemAttribute *node) -+{ -+ WRITE_NODE_TYPE("SEVALITEMATTRIBUTE"); ++ WRITE_UINT_FIELD(relperms); ++ WRITE_UINT_FIELD(nattrs); + -+ WRITE_UINT_FIELD(perms); -+ -+ WRITE_OID_FIELD(relid); -+ WRITE_BOOL_FIELD(inh); -+ WRITE_INT_FIELD(attno); -+} -+ -+static void -+_outSEvalItemProcedure(StringInfo str, SEvalItemProcedure *node) -+{ -+ WRITE_NODE_TYPE("SEVALITEMPROCEDURE"); -+ -+ WRITE_UINT_FIELD(perms); -+ -+ WRITE_OID_FIELD(funcid); ++ appendStringInfo(str, " :attperms ["); ++ for (i = 0; i < node->nattrs; i++) ++ appendStringInfo(str, " %u", node->attperms[i]); ++ appendStringInfo(str, " ]"); +} /* * _outNode - -@@ -2438,6 +2483,15 @@ _outNode(StringInfo str, void *obj) +@@ -2439,6 +2470,9 @@ _outNode(StringInfo str, void *obj) case T_XmlSerialize: _outXmlSerialize(str, obj); break; -+ case T_SEvalItemRelation: -+ _outSEvalItemRelation(str, obj); -+ break; -+ case T_SEvalItemAttribute: -+ _outSEvalItemAttribute(str, obj); -+ break; -+ case T_SEvalItemProcedure: -+ _outSEvalItemProcedure(str, obj); ++ case T_SelinuxEvalItem: ++ _outSelinuxEvalItem(str, obj); + break; default: diff -rpNU3 base/src/backend/nodes/readfuncs.c sepgsql/src/backend/nodes/readfuncs.c --- base/src/backend/nodes/readfuncs.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/nodes/readfuncs.c 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/nodes/readfuncs.c 2009-01-21 17:02:57.000000000 +0900 @@ -24,6 +24,7 @@ #include "nodes/parsenodes.h" @@ -3046,7 +3420,7 @@ diff -rpNU3 base/src/backend/nodes/readfuncs.c sepgsql/src/backend/nodes/readfun READ_DONE(); } -@@ -1003,10 +1005,52 @@ _readRangeTblEntry(void) +@@ -1003,10 +1005,49 @@ _readRangeTblEntry(void) READ_BOOL_FIELD(inFromCl); READ_UINT_FIELD(requiredPerms); READ_OID_FIELD(checkAsUser); @@ -3058,57 +3432,50 @@ diff -rpNU3 base/src/backend/nodes/readfuncs.c sepgsql/src/backend/nodes/readfun +/* + * Stuff from nodes/security.h + */ -+static SEvalItemRelation * -+_readSEvalItemRelation(void) ++static SelinuxEvalItem * ++_readSelinuxEvalItem(void) +{ -+ READ_LOCALS(SEvalItemRelation); ++ int i; + -+ READ_UINT_FIELD(perms); ++ READ_LOCALS(SelinuxEvalItem); + + READ_OID_FIELD(relid); + READ_BOOL_FIELD(inh); + -+ READ_DONE(); -+} ++ READ_UINT_FIELD(relperms); ++ READ_UINT_FIELD(nattrs); + -+static SEvalItemAttribute * -+_readSEvalItemAttribute(void) -+{ -+ READ_LOCALS(SEvalItemAttribute); ++ /* ++ * TODO: This part should be moved to readArray() ? ++ */ ++ local_node->attperms = palloc0(local_node->nattrs * sizeof(uint32)); + -+ READ_UINT_FIELD(perms); -+ -+ READ_OID_FIELD(relid); -+ READ_BOOL_FIELD(inh); -+ READ_INT_FIELD(attno); -+ -+ READ_DONE(); -+} -+ -+static SEvalItemProcedure * -+_readSEvalItemProcedure(void) -+{ -+ READ_LOCALS(SEvalItemProcedure); -+ -+ READ_UINT_FIELD(perms); -+ -+ READ_OID_FIELD(funcid); ++ 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 -@@ -1124,6 +1168,12 @@ parseNodeString(void) +@@ -1124,6 +1165,8 @@ parseNodeString(void) return_value = _readNotifyStmt(); else if (MATCH("DECLARECURSOR", 13)) return_value = _readDeclareCursorStmt(); -+ else if (MATCH("SEVALITEMRELATION", 17)) -+ return_value = _readSEvalItemRelation(); -+ else if (MATCH("SEVALITEMATTRIBUTE", 18)) -+ return_value = _readSEvalItemAttribute(); -+ else if (MATCH("SEVALITEMPROCEDURE", 18)) -+ return_value = _readSEvalItemProcedure(); ++ else if (MATCH("SELINUXEVALITEM", 15)) ++ return_value = _readSelinuxEvalItem(); else { elog(ERROR, "badly formatted node string \"%.32s\"...", token); @@ -3130,25 +3497,8 @@ diff -rpNU3 base/src/backend/optimizer/plan/createplan.c sepgsql/src/backend/opt * quals. diff -rpNU3 base/src/backend/optimizer/plan/planner.c sepgsql/src/backend/optimizer/plan/planner.c --- base/src/backend/optimizer/plan/planner.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql/src/backend/optimizer/plan/planner.c 2008-06-14 02:36:58.000000000 +0900 -@@ -38,6 +38,7 @@ - #include "parser/parse_expr.h" - #include "parser/parse_oper.h" - #include "parser/parsetree.h" -+#include "security/pgace.h" - #include "utils/lsyscache.h" - #include "utils/syscache.h" - -@@ -97,7 +98,7 @@ planner(Query *parse, int cursorOptions, - { - PlannedStmt *result; - -- if (planner_hook) -+ if (planner_hook && pgaceIsAllowPlannerHook()) - result = (*planner_hook) (parse, cursorOptions, boundParams); - else - result = standard_planner(parse, cursorOptions, boundParams); -@@ -197,6 +198,7 @@ standard_planner(Query *parse, int curso ++++ sepgsql/src/backend/optimizer/plan/planner.c 2008-11-24 20:26:40.000000000 +0900 +@@ -197,6 +197,7 @@ standard_planner(Query *parse, int curso result->rowMarks = parse->rowMarks; result->relationOids = glob->relationOids; result->nParamExec = list_length(glob->paramlist); @@ -3156,6 +3506,27 @@ diff -rpNU3 base/src/backend/optimizer/plan/planner.c sepgsql/src/backend/optimi return result; } +diff -rpNU3 base/src/backend/optimizer/util/clauses.c sepgsql/src/backend/optimizer/util/clauses.c +--- base/src/backend/optimizer/util/clauses.c 2008-09-25 15:09:40.000000000 +0900 ++++ sepgsql/src/backend/optimizer/util/clauses.c 2008-12-28 01:06:59.000000000 +0900 +@@ -39,6 +39,7 @@ + #include "parser/parse_coerce.h" + #include "parser/parse_expr.h" + #include "tcop/tcopprot.h" ++#include "security/pgace.h" + #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/datum.h" +@@ -3057,6 +3058,9 @@ inline_function(Oid funcid, Oid result_t + 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. diff -rpNU3 base/src/backend/optimizer/util/relnode.c sepgsql/src/backend/optimizer/util/relnode.c --- base/src/backend/optimizer/util/relnode.c 2008-01-07 23:51:33.000000000 +0900 +++ sepgsql/src/backend/optimizer/util/relnode.c 2008-06-14 02:36:58.000000000 +0900 @@ -3168,8 +3539,8 @@ diff -rpNU3 base/src/backend/optimizer/util/relnode.c sepgsql/src/backend/optimi /* Check type of rtable entry */ switch (rte->rtekind) diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze.c ---- base/src/backend/parser/analyze.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/parser/analyze.c 2008-06-18 17:25:44.000000000 +0900 +--- base/src/backend/parser/analyze.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/parser/analyze.c 2009-02-02 11:58:34.000000000 +0900 @@ -24,6 +24,7 @@ #include "postgres.h" @@ -3186,7 +3557,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze typedef struct -@@ -563,14 +565,15 @@ transformInsertStmt(ParseState *pstate, +@@ -612,14 +614,15 @@ transformInsertStmt(ParseState *pstate, Expr *expr = (Expr *) lfirst(lc); ResTarget *col; TargetEntry *tle; @@ -3204,7 +3575,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze qry->targetList = lappend(qry->targetList, tle); icols = lnext(icols); -@@ -668,6 +671,45 @@ transformInsertRow(ParseState *pstate, L +@@ -717,6 +720,46 @@ transformInsertRow(ParseState *pstate, L return result; } @@ -3224,7 +3595,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze + continue; + + attr = SystemAttributeByName(tle->resname, relhasoids); -+ if (attr && SystemAttributeIsWritable(attr->attnum, relhasoids)) ++ if (attr && SystemAttributeIsWritable(attr->attnum)) + { + uint32 mask = (1<<(-attr->attnum)); + @@ -3235,13 +3606,14 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze + + 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); ++ tle->expr = ++ (Expr *) coerce_to_target_type(pstate, ++ (Node *) tle->expr, ++ exprType((Node *) tle->expr), ++ attr->atttypid, ++ attr->atttypmod, ++ COERCION_IMPLICIT, ++ COERCE_IMPLICIT_CAST); + } + tle->resjunk = true; + } @@ -3250,7 +3622,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze /* * transformSelectStmt - -@@ -734,6 +776,7 @@ transformSelectStmt(ParseState *pstate, +@@ -783,6 +826,7 @@ transformSelectStmt(ParseState *pstate, if (stmt->intoClause) { qry->intoClause = stmt->intoClause; @@ -3260,7 +3632,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze } diff -rpNU3 base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y --- base/src/backend/parser/gram.y 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/parser/gram.y 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/parser/gram.y 2008-12-28 01:06:59.000000000 +0900 @@ -56,6 +56,7 @@ #include "commands/defrem.h" #include "nodes/makefuncs.h" @@ -3382,7 +3754,7 @@ diff -rpNU3 base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y ; -@@ -8736,6 +8772,26 @@ target_el: a_expr AS ColLabel +@@ -8736,6 +8772,28 @@ target_el: a_expr AS ColLabel } ; @@ -3400,10 +3772,12 @@ diff -rpNU3 base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y +SecurityItem: + IDENT '=' Sconst + { -+ DefElem *n = pgaceGramSecurityItem($1, $3); -+ if (n == NULL) ++ DefElem *node = makeDefElem($1, (Node *) makeString($3)); ++ ++ if (!pgaceIsGramSecurityItem(node)) + yyerror("syntax error"); -+ $$ = n; ++ ++ $$ = node; + } + ; @@ -3411,7 +3785,7 @@ diff -rpNU3 base/src/backend/parser/gram.y sepgsql/src/backend/parser/gram.y * diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/parse_target.c --- base/src/backend/parser/parse_target.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/parser/parse_target.c 2008-07-11 14:10:51.000000000 +0900 ++++ sepgsql/src/backend/parser/parse_target.c 2008-12-05 17:58:33.000000000 +0900 @@ -14,6 +14,7 @@ */ #include "postgres.h" @@ -3428,7 +3802,7 @@ diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/pa #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/typcache.h" -@@ -333,16 +335,31 @@ transformAssignedExpr(ParseState *pstate +@@ -333,16 +335,33 @@ transformAssignedExpr(ParseState *pstate Oid attrtype; /* type of target column */ int32 attrtypmod; Relation rd = pstate->p_target_relation; @@ -3436,54 +3810,51 @@ diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/pa 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 (attrno > 0) + { + attrtype = attnumTypeId(rd, attrno); + attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod; + } -+ else if (SystemAttributeIsWritable(attrno, relhasoids)) -+ { -+ Form_pg_attribute attr; -+ -+ attr = SystemAttributeDefinition(attrno, relhasoids); -+ 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))); -- attrtype = attnumTypeId(rd, attrno); -- attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod; -+ return NULL; /* compiler kindness */ ++ 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 -@@ -467,6 +484,9 @@ updateTargetListEntry(ParseState *pstate - List *indirection, - int location) - { -+ bool relhasoids -+ = RelationGetForm(pstate->p_target_relation)->relhasoids; -+ - /* Fix up expression as needed */ - tle->expr = transformAssignedExpr(pstate, - tle->expr, -@@ -483,6 +503,9 @@ updateTargetListEntry(ParseState *pstate +@@ -483,6 +502,9 @@ updateTargetListEntry(ParseState *pstate */ tle->resno = (AttrNumber) attrno; tle->resname = colname; + -+ if (SystemAttributeIsWritable(attrno, relhasoids)) ++ if (SystemAttributeIsWritable(attrno)) + tle->resjunk = true; } -@@ -749,6 +772,7 @@ checkInsertTargets(ParseState *pstate, L +@@ -749,6 +771,7 @@ checkInsertTargets(ParseState *pstate, L Bitmapset *wholecols = NULL; Bitmapset *partialcols = NULL; ListCell *tl; @@ -3491,7 +3862,7 @@ diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/pa foreach(tl, cols) { -@@ -757,14 +781,40 @@ checkInsertTargets(ParseState *pstate, L +@@ -757,14 +780,37 @@ checkInsertTargets(ParseState *pstate, L int attrno; /* Lookup column name, ereport on failure */ @@ -3508,10 +3879,7 @@ diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/pa + } + else if (attrno < 0) + { -+ bool relhasoids -+ = RelationGetForm(pstate->p_target_relation)->relhasoids; -+ -+ if (SystemAttributeIsWritable(attrno, relhasoids)) ++ if (SystemAttributeIsWritable(attrno)) + { + uint32 mask = (1<<(-attrno)); + @@ -3651,7 +4019,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas { diff -rpNU3 base/src/backend/rewrite/rewriteHandler.c sepgsql/src/backend/rewrite/rewriteHandler.c --- base/src/backend/rewrite/rewriteHandler.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql/src/backend/rewrite/rewriteHandler.c 2008-11-05 10:01:30.000000000 +0900 ++++ sepgsql/src/backend/rewrite/rewriteHandler.c 2009-01-16 10:33:08.000000000 +0900 @@ -24,6 +24,7 @@ #include "rewrite/rewriteDefine.h" #include "rewrite/rewriteHandler.h" @@ -3660,17 +4028,16 @@ diff -rpNU3 base/src/backend/rewrite/rewriteHandler.c sepgsql/src/backend/rewrit #include "utils/builtins.h" #include "utils/lsyscache.h" #include "commands/trigger.h" -@@ -1919,5 +1920,7 @@ QueryRewrite(Query *parsetree) +@@ -1919,5 +1920,5 @@ QueryRewrite(Query *parsetree) if (!foundOriginalQuery && lastInstead != NULL) lastInstead->canSetTag = true; -+ results = pgaceProxyQuery(results); -+ - return results; +- return results; ++ return pgacePostQueryRewrite(results); } diff -rpNU3 base/src/backend/security/Makefile sepgsql/src/backend/security/Makefile --- base/src/backend/security/Makefile 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/Makefile 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/security/Makefile 2009-01-14 15:33:08.000000000 +0900 @@ -0,0 +1,32 @@ +# +# src/backend/security/Makefile @@ -3683,7 +4050,7 @@ diff -rpNU3 base/src/backend/security/Makefile sepgsql/src/backend/security/Make +include $(top_builddir)/src/Makefile.global + + -+OBJS := pgaceCommon.o ++OBJS := pgaceCommon.o pgaceHooks.o + +ifeq ($(enable_selinux), yes) +OBJS += sepgsql/avc.o sepgsql/core.o sepgsql/hooks.o \ @@ -3706,8 +4073,8 @@ diff -rpNU3 base/src/backend/security/Makefile sepgsql/src/backend/security/Make +endif diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security/pgaceCommon.c --- base/src/backend/security/pgaceCommon.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/pgaceCommon.c 2008-10-08 17:12:02.000000000 +0900 -@@ -0,0 +1,786 @@ ++++ sepgsql/src/backend/security/pgaceCommon.c 2009-01-14 15:25:24.000000000 +0900 +@@ -0,0 +1,814 @@ + +/* + * src/backend/security/pgaceCommon.c @@ -3747,16 +4114,33 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + * GUC Parameter Support + *****************************************************************************/ + -+/* -+ * pgaceShowsFeatureIdentifier -+ * -+ * It is invoked when 'pgace_feature' is refered, and it has to return -+ * an identifier of the guest. -+ */ ++int pgace_feature; ++char *pgace_feature_string; ++ +const char * -+pgaceShowSecurityFeature(void) ++pgaceAssignFeatureString(const char *value, bool doit, GucSource source) +{ -+ return pgaceSecurityFeatureIdentity(); ++ char *result; ++ ++ if (strcmp(value, "none") == 0) ++ { ++ pgace_feature = PGACE_FEATURE_NONE; ++ result = strdup(value); ++ } ++#ifdef HAVE_SELINUX ++ else if (strcmp(value, "selinux") == 0) ++ { ++ pgace_feature = PGACE_FEATURE_SELINUX; ++ result = strdup(value); ++ } ++#endif ++ else ++ { ++ pgace_feature = PGACE_FEATURE_NONE; ++ result = strdup("none"); ++ } ++ ++ return result; +} + +/***************************************************************************** @@ -3826,11 +4210,11 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security +} + +void -+pgaceCreateRelationCommon(Relation rel, HeapTuple tuple, List *pgace_attr_list) ++pgaceCreateRelationCommon(Relation rel, HeapTuple tuple, List *pgaceAttrList) +{ + ListCell *l; + -+ foreach(l, pgace_attr_list) ++ foreach(l, pgaceAttrList) + { + DefElem *defel = (DefElem *) lfirst(l); + @@ -3845,12 +4229,12 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + +void +pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple, -+ List *pgace_attr_list) ++ List *pgaceAttrList) +{ + Form_pg_attribute attr = (Form_pg_attribute) GETSTRUCT(tuple); + ListCell *l; + -+ foreach(l, pgace_attr_list) ++ foreach(l, pgaceAttrList) + { + DefElem *defel = lfirst(l); + @@ -4039,7 +4423,7 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + earlySeclabel *es, *_es; + Oid meta_sid; + Datum value; -+ char isnull; ++ bool isnull; + + if (!earlySeclabelList) + return; @@ -4056,11 +4440,12 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + _es = es->next; + + value = DirectFunctionCall1(textin, CStringGetDatum(es->label)); -+ isnull = ' '; -+ tuple = heap_formtuple(RelationGetDescr(rel), &value, &isnull); ++ isnull = false; ++ tuple = heap_form_tuple(RelationGetDescr(rel), &value, &isnull); + + HeapTupleSetOid(tuple, es->sid); -+ HeapTupleSetSecurity(tuple, meta_sid); ++ if (HeapTupleHasSecLabel(tuple)) ++ HeapTupleSetSecLabel(tuple, meta_sid); + + simple_heap_insert(rel, tuple); + CatalogIndexInsert(ind, tuple); @@ -4087,20 +4472,6 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + Oid labelOid, labelSid; + HeapTuple tuple; + -+ if (!raw_label) -+ { -+ raw_label = pgaceUnlabeledSecurityLabel(); -+ if (!raw_label) -+ elog(ERROR, "unlabeled security attribute is unavailable"); -+ } -+ -+ if (!pgaceCheckValidSecurityLabel(raw_label)) -+ { -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("%s: invalid security attribute", raw_label))); -+ } -+ + if (IsBootstrapProcessingMode()) + return earlySecurityLabelToSid(raw_label); + @@ -4124,13 +4495,18 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + CatalogIndexState ind; + char *slabel; + Datum labelTxt; -+ char isnull; ++ bool isnull; + + rel = heap_open(SecurityRelationId, RowExclusiveLock); + + slabel = pgaceSecurityLabelOfLabel(); + -+ if (!strcmp(raw_label, slabel)) ++ if (!slabel) ++ { ++ labelSid = InvalidOid; ++ labelOid = GetNewOid(rel); ++ } ++ else if (!strcmp(raw_label, slabel)) + { + labelOid = labelSid = GetNewOid(rel); + } @@ -4143,10 +4519,11 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + ind = CatalogOpenIndexes(rel); + + labelTxt = CStringGetTextDatum(raw_label); -+ isnull = ' '; -+ tuple = heap_formtuple(RelationGetDescr(rel), -+ &labelTxt, &isnull); -+ HeapTupleSetSecurity(tuple, labelSid); ++ isnull = false; ++ tuple = heap_form_tuple(RelationGetDescr(rel), ++ &labelTxt, &isnull); ++ if (HeapTupleHasSecLabel(tuple)) ++ HeapTupleSetSecLabel(tuple, labelSid); + HeapTupleSetOid(tuple, labelOid); + + simple_heap_insert(rel, tuple); @@ -4180,6 +4557,11 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security +{ + 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); +} + @@ -4190,27 +4572,24 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + * in raw-format, without cosmetic translation. + */ +char * -+pgaceLookupSecurityLabel(Oid security_id) ++pgaceLookupSecurityLabel(Oid sid) +{ + HeapTuple tuple; + Datum labelTxt; -+ char *label, isnull; ++ char *label; ++ bool isnull; + -+ if (security_id == InvalidOid) -+ goto unlabeled; ++ if (!OidIsValid(sid)) ++ return NULL; + + if (IsBootstrapProcessingMode()) -+ { -+ label = earlySidToSecurityLabel(security_id); -+ if (!label) -+ goto unlabeled; -+ return label; -+ } ++ return earlySidToSecurityLabel(sid); + + tuple = SearchSysCache(SECURITYOID, -+ ObjectIdGetDatum(security_id), 0, 0, 0); ++ ObjectIdGetDatum(sid), ++ 0, 0, 0); + if (!HeapTupleIsValid(tuple)) -+ goto unlabeled; ++ return NULL; + + labelTxt = SysCacheGetAttr(SECURITYOID, + tuple, Anum_pg_security_seclabel, &isnull); @@ -4218,25 +4597,32 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + label = TextDatumGetCString(labelTxt); + ReleaseSysCache(tuple); + -+ if (pgaceCheckValidSecurityLabel(label)) -+ return label; -+ -+unlabeled: -+ label = pgaceUnlabeledSecurityLabel(); -+ if (!label) -+ elog(ERROR, "unlabeled security attribute is unavailable"); -+ + return label; +} + +char * -+pgaceSidToSecurityLabel(Oid security_id) ++pgaceSidToSecurityLabel(Oid sid) +{ -+ char *label = pgaceLookupSecurityLabel(security_id); ++ 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 + *****************************************************************************/ @@ -4258,7 +4644,7 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + ScanKeyData skey; + SysScanDesc scan; + HeapTuple tuple; -+ Oid security_id; ++ Oid sid; + + rel = heap_open(LargeObjectRelationId, AccessShareLock); + @@ -4275,12 +4661,12 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", loid))); + pgaceLargeObjectGetSecurity(rel, tuple); -+ security_id = HeapTupleGetSecurity(tuple); ++ sid = HeapTupleGetSecLabel(tuple); + + systable_endscan(scan); + heap_close(rel, AccessShareLock); + -+ return CStringGetTextDatum(pgaceSidToSecurityLabel(security_id)); ++ return CStringGetTextDatum(pgaceSidToSecurityLabel(sid)); +} + +/* @@ -4300,11 +4686,11 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + SysScanDesc sd; + HeapTuple oldtup, newtup; + CatalogIndexState indstate; -+ Oid security_id; ++ Oid sid; + List *okList = NIL; + bool found = false; + -+ security_id = pgaceSecurityLabelToSid(TextDatumGetCString(labelTxt)); ++ sid = pgaceSecurityLabelToSid(TextDatumGetCString(labelTxt)); + + ScanKeyInit(&skey, + Anum_pg_largeobject_loid, @@ -4324,14 +4710,14 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + ListCell *l; + + newtup = heap_copytuple(oldtup); -+ HeapTupleSetSecurity(newtup, security_id); ++ HeapTupleSetSecLabel(newtup, sid); + + foreach (l, okList) + { -+ if (HeapTupleGetSecurity(oldtup) == lfirst_oid(l)) ++ if (HeapTupleGetSecLabel(oldtup) == lfirst_oid(l)) + goto skip; /* already checked */ + } -+ okList = lappend_oid(okList, HeapTupleGetSecurity(oldtup)); ++ okList = lappend_oid(okList, HeapTupleGetSecLabel(oldtup)); + + pgaceLargeObjectSetSecurity(rel, newtup, oldtup); + skip: @@ -4421,83 +4807,1586 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security + * are not compiled and linked when it is disabled. + * It can cause a build problem in other environments. + */ -+ +#ifndef HAVE_SELINUX + +static Datum -+sepgsql_is_disabled(const char *function) ++unavailable_function(const char *fn_name, int error_code) +{ + ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("%s is not implemented", function))); ++ (errcode(error_code), ++ errmsg("%s is not available", fn_name))); + PG_RETURN_VOID(); +} + +Datum +sepgsql_getcon(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_getservcon(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_get_user(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_get_role(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_get_type(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_get_range(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_set_user(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_set_role(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_set_type(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +Datum +sepgsql_set_range(PG_FUNCTION_ARGS) +{ -+ return sepgsql_is_disabled(__FUNCTION__); ++ return unavailable_function(__FUNCTION__, ++ ERRCODE_SELINUX_ERROR); +} + +#endif /* HAVE_SELINUX */ +diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/pgaceHooks.c +--- base/src/backend/security/pgaceHooks.c 1970-01-01 09:00:00.000000000 +0900 ++++ sepgsql/src/backend/security/pgaceHooks.c 2009-01-21 17:26:07.000000000 +0900 +@@ -0,0 +1,1490 @@ ++/* ++ * 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) ++ * { ++ * 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. ++ * ++ * 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) ++{ ++ 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) ++{ ++ 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) ++{ ++ 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) ++{ ++ 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) ++{ ++ 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) ++{ ++ 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 *pgace_private) ++{ ++ 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 pgace_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) ++{ ++ 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 ++ ******************************************************************/ ++ ++/* ++ * 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 -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security/sepgsql/avc.c --- base/src/backend/security/sepgsql/avc.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/avc.c 2008-10-01 11:04:40.000000000 +0900 -@@ -0,0 +1,1108 @@ ++++ sepgsql/src/backend/security/sepgsql/avc.c 2009-01-22 14:10:59.000000000 +0900 +@@ -0,0 +1,1202 @@ + +/* + * src/backend/security/sepgsql/avc.c @@ -4620,6 +6509,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + { "relabelto", DB_PROCEDURE__RELABELTO }, + { "execute", DB_PROCEDURE__EXECUTE }, + { "entrypoint", DB_PROCEDURE__ENTRYPOINT }, ++ { "install", DB_PROCEDURE__INSTALL }, + { NULL, 0UL }, + } + }, @@ -4670,8 +6560,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + }, +}; + -+#define NUM_SELINUX_CATALOG (sizeof(selinux_catalog) / sizeof(selinux_catalog[0])) -+ +static MemoryContext AvcMemCtx; + +#define AVC_HASH_NUM_SLOTS 256 @@ -4754,7 +6642,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + access_vector_t internal; + access_vector_t external; + } av_perms[sizeof(access_vector_t) * 8]; -+ } catalog[NUM_SELINUX_CATALOG]; ++ } catalog[lengthof(selinux_catalog)]; +} *selinux_state = NULL; + +Size @@ -4773,41 +6661,40 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security +static void +load_class_av_mapping(void) +{ -+ security_class_t tclass; -+ access_vector_t av_perms; + int i, j; + -+ for (i = 0; i < NUM_SELINUX_CATALOG; i++) -+ { -+ tclass = string_to_security_class(selinux_catalog[i].tclass.name); -+ if (!tclass) -+ tclass = selinux_catalog[i].tclass.internal; ++ 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 = tclass; ++ 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++) + { -+ av_perms = -+ string_to_av_perm(tclass, selinux_catalog[i].av_perms[j].name); -+ if (!av_perms) -+ av_perms = selinux_catalog[i].av_perms[j].internal; -+ + selinux_state->catalog[i].av_perms[j].internal + = selinux_catalog[i].av_perms[j].internal; -+ selinux_state->catalog[i].av_perms[j].external = av_perms; ++ 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 < NUM_SELINUX_CATALOG; 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; @@ -4815,39 +6702,66 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + 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) ++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 < NUM_SELINUX_CATALOG; i++) ++ 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 & e_perms) != 0) ++ 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 < NUM_SELINUX_CATALOG; i++) ++ for (i = 0; i < lengthof(selinux_catalog); i++) + { + if (selinux_catalog[i].tclass.internal == tclass) + return selinux_catalog[i].tclass.name; + } + /* -+ * tclass is always same as external one, for kernel object classes ++ * tclass is stable for kernel object classes. + */ + return security_class_to_string(tclass); +} @@ -4857,7 +6771,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security +{ + int i, j; + -+ for (i = 0; i < NUM_SELINUX_CATALOG; i++) ++ for (i = 0; i < lengthof(selinux_catalog); i++) + { + if (selinux_catalog[i].tclass.internal == tclass) + { @@ -4872,17 +6786,15 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + } + } + /* -+ * tclass is always same as external one, for kernel object classes ++ * tclass/perms are stable for kernel object classes. + */ + return security_av_perm_to_string(tclass, perm); +} + +/* + * sepgsql_avc_reset -+ * -+ * This function clears all current avc entries, and update its version. ++ * clears all uAVC entries and update its version. + */ -+ +static void +sepgsql_avc_reset(void) +{ @@ -4891,17 +6803,26 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + LWLockAcquire(SepgsqlAvcLock, LW_SHARED); + + avc_version = selinux_state->version; -+ if (!strcmp(sepostgresql_mode, "default")) ++ switch (sepostgresql_mode) ++ { ++ case SEPGSQL_MODE_DEFAULT: + avc_enforcing = selinux_state->enforcing; -+ else if (!strcmp(sepostgresql_mode, "permissive")) ++ break; ++ case SEPGSQL_MODE_PERMISSIVE: + avc_enforcing = false; -+ else if (!strcmp(sepostgresql_mode, "enforcing")) -+ avc_enforcing = true; -+ else -+ elog(FATAL, "SELinux: undefined state (sepostgresql = %s)", sepostgresql_mode); ++ 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()); @@ -4909,9 +6830,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + +/* + * sepgsql_avc_reclaim -+ * -+ * This function reclaims recently not-used avc entries, -+ * when the number of caches overs AVC_HASH_NUM_NODES ++ * reclaims recently unused uAVC entries, when the number of ++ * caches overs AVC_HASH_NUM_NODES. + */ +static void +sepgsql_avc_reclaim(void) @@ -4951,10 +6871,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + +/* + * avc_audit_common -+ * -+ * This function makes an audit message on the given Cstring buffer, -+ * based on the given av_decision (which is the result of permission -+ * checks). ++ * 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, @@ -5003,6 +6921,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + 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) @@ -5045,14 +6969,15 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security +} + +/* -+ * sepgsql_avc_compute -+ * -+ * This function compute an avc_decision cache for the given subject/target -+ * context and object class, based on results of inquiries to SELinux. ++ * 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) ++static avc_datum * ++avc_make_entry(Oid tsid, security_class_t tclass) +{ + security_context_t scontext, tcontext, ncontext; + security_class_t e_tclass; @@ -5071,6 +6996,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + + scontext = current_avc_page->scontext; + tcontext = pgaceLookupSecurityLabel(tsid); ++ if (!tcontext || !pgaceCheckValidSecurityLabel(tcontext)) ++ tcontext = pgaceUnlabeledSecurityLabel(); + + LWLockAcquire(SepgsqlAvcLock, LW_SHARED); + @@ -5083,6 +7010,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + "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), @@ -5091,12 +7024,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + scontext, tcontext, sepgsql_class_to_string(tclass)))); + pfree(tcontext); + -+ cache->allowed = trans_to_internal_perms(e_tclass, avd.allowed); -+ cache->decided = trans_to_internal_perms(e_tclass, avd.decided); -+ cache->auditallow = trans_to_internal_perms(e_tclass, avd.auditallow); -+ cache->auditdeny = trans_to_internal_perms(e_tclass, avd.auditdeny); -+ cache->hot_cache = true; -+ + LWLockRelease(SepgsqlAvcLock); + + PG_TRY(); @@ -5117,6 +7044,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + current_avc_page->slot[index] + = lcons(cache, current_avc_page->slot[index]); + ++ avc_datum_count++; ++ + MemoryContextSwitchTo(oldctx); + + return cache; @@ -5156,8 +7085,26 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + +/* + * sepgsqlAvcSwitchClientContext() ++ * switches current avc_page. + * -+ * This function switchs avc_page for given context ++ * 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) +{ @@ -5201,6 +7148,11 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + 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, @@ -5214,6 +7166,11 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + 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, @@ -5227,6 +7184,14 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + 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) +{ @@ -5236,11 +7201,17 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + { + if (!cache) + cache = avc_make_entry(tsid, tclass); -+ cache->nsid = pgaceLookupSecurityId(cache->ncontext); ++ 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) +{ @@ -5253,9 +7224,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security +} + +/* -+ * sepgsqlAvcInit -+ * -+ * Initialize local memory context and assign shared memory segment ++ * sepgsql_shmem_init ++ * attaches shared memory segment. + */ +static void +sepgsql_shmem_init(void) @@ -5279,6 +7249,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + } +} + ++/* ++ * sepgsqlAvcInit ++ * initialize local uAVC facility. ++ */ +void +sepgsqlAvcInit(void) +{ @@ -5299,7 +7273,16 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security +} + +/* -+ * No cached interfaces ++ * 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, @@ -5330,10 +7313,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security + svcon, tvcon, security_class_to_string(e_tclass)))); + + cache.tclass = tclass; -+ cache.allowed = trans_to_internal_perms(e_tclass, avd.allowed); -+ cache.decided = trans_to_internal_perms(e_tclass, avd.decided); -+ cache.auditallow = trans_to_internal_perms(e_tclass, avd.auditallow); -+ cache.auditdeny = trans_to_internal_perms(e_tclass, avd.auditdeny); ++ 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); @@ -5608,8 +7591,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/avc.c sepgsql/src/backend/security +} diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/security/sepgsql/core.c --- base/src/backend/security/sepgsql/core.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/core.c 2008-09-29 19:49:07.000000000 +0900 -@@ -0,0 +1,663 @@ ++++ sepgsql/src/backend/security/sepgsql/core.c 2009-01-24 22:44:20.000000000 +0900 +@@ -0,0 +1,672 @@ + +/* + * src/backend/security/sepgsqlCore.c @@ -5626,9 +7609,13 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit +#include "libpq/libpq.h" +#include "miscadmin.h" +#include "security/pgace.h" ++#include "utils/builtins.h" +#include "utils/syscache.h" +#include + ++int sepostgresql_mode; ++char *sepostgresql_mode_string; ++ +static security_context_t serverContext = NULL; +static security_context_t clientContext = NULL; +static security_context_t unlabeledContext = NULL; @@ -5650,29 +7637,23 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit +const security_context_t +sepgsqlGetDatabaseContext(void) +{ -+ security_context_t dcontext; ++ security_context_t result; + + if (IsBootstrapProcessingMode()) + { -+ security_context_t tmp; ++ static security_context_t dbcontext = NULL; + -+ if (security_compute_create_raw(sepgsqlGetClientContext(), -+ sepgsqlGetClientContext(), -+ SECCLASS_DB_DATABASE, &tmp) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get database context"))); -+ PG_TRY(); -+ { -+ dcontext = pstrdup(tmp); -+ } -+ PG_CATCH(); -+ { -+ freecon(tmp); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(tmp); ++ 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 + { @@ -5684,25 +7665,27 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId); + -+ dcontext = pgaceLookupSecurityLabel(HeapTupleGetSecurity(tuple)); ++ result = pgaceLookupSecurityLabel(HeapTupleGetSecLabel(tuple)); ++ if (!result || !pgaceCheckValidSecurityLabel(result)) ++ result = pgaceUnlabeledSecurityLabel(); + + ReleaseSysCache(tuple); + } + -+ return dcontext; ++ return result; +} + +Oid +sepgsqlGetDatabaseSecurityId(void) +{ -+ Oid security_id; ++ Oid sid; + + if (IsBootstrapProcessingMode()) + { + security_context_t dcontext + = sepgsqlGetDatabaseContext(); + -+ security_id = pgaceSecurityLabelToSid(dcontext); ++ sid = pgaceSecurityLabelToSid(dcontext); + } + else + { @@ -5714,12 +7697,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "SELinux: cache lookup failed for database: %u", MyDatabaseId); + -+ security_id = HeapTupleGetSecurity(tuple); ++ sid = HeapTupleGetSecLabel(tuple); + + ReleaseSysCache(tuple); + } + -+ return security_id; ++ return sid; +} + +const security_context_t @@ -5876,6 +7859,27 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit + * - disabled : It disables SE-PostgreSQL feature. It works as if + * original PostgreSQL + */ ++const char *sepgsqlAssignModeString(const char *value, bool doit, GucSource source) ++{ ++ SepgsqlModeType config_mode = SEPGSQL_MODE_DEFAULT; ++ ++ if (strcmp(value, "default") == 0) ++ config_mode = SEPGSQL_MODE_DEFAULT; ++ else if (strcmp(value, "enforcing") == 0) ++ config_mode = SEPGSQL_MODE_ENFORCING; ++ else if (strcmp(value, "permissive") == 0) ++ config_mode = SEPGSQL_MODE_PERMISSIVE; ++ else if (strcmp(value, "disabled") == 0) ++ config_mode = SEPGSQL_MODE_DISABLED; ++ else ++ ereport(GUC_complaint_elevel(source), ++ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ++ "SELinux: unexpected mode: %s", value)); ++ if (doit) ++ sepostgresql_mode = config_mode; ++ ++ return value; ++} + +bool +sepgsqlIsEnabled(void) @@ -5884,30 +7888,18 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit + + if (enabled < 0) + { -+ if (strcmp(sepostgresql_mode, "disabled") == 0) ++ if (sepostgresql_mode == SEPGSQL_MODE_DISABLED) + enabled = 0; + else + { -+ int rc = is_selinux_enabled(); -+ -+ if (strcmp(sepostgresql_mode, "default") == 0) -+ enabled = rc; -+ else if (strcmp(sepostgresql_mode, "permissice") == 0 -+ || strcmp(sepostgresql_mode, "enforcing") == 0) -+ { -+ if (rc == 0) -+ ereport(FATAL, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: disabled in kernel, but sepostgresql = %s", -+ sepostgresql_mode))); -+ enabled = 1; -+ } -+ 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: unknown state sepostgresql = %s", -+ sepostgresql_mode))); ++ errmsg("SELinux: disabled in kernel, but sepostgresql = %s", ++ SEPGSQL_MODE_ENFORCING ? "enforcing" : "permissive"))); + } + } + } @@ -5926,7 +7918,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit + security_context_t context; + Datum labelTxt; + -+ if (!sepgsqlIsEnabled()) ++ if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled()) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux: disabled now"))); @@ -5961,7 +7953,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit + security_context_t context; + Datum labelTxt; + -+ if (!sepgsqlIsEnabled()) ++ if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled()) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux: disabled now"))); @@ -5991,7 +7983,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit +{ + security_context_t raw_context; + -+ if (!sepgsqlIsEnabled()) ++ if (pgace_feature != PGACE_FEATURE_SELINUX || !sepgsqlIsEnabled()) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), + errmsg("SELinux: disabled now"))); @@ -6275,8 +8267,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit +} diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/security/sepgsql/hooks.c --- base/src/backend/security/sepgsql/hooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/hooks.c 2008-10-31 17:01:56.000000000 +0900 -@@ -0,0 +1,879 @@ ++++ sepgsql/src/backend/security/sepgsql/hooks.c 2009-01-22 10:40:54.000000000 +0900 +@@ -0,0 +1,1018 @@ +/* + * src/backend/security/sepgsql/hooks.c + * implementations of PGACE framework @@ -6291,9 +8283,11 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +#include "access/genam.h" +#include "access/skey.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" @@ -6308,23 +8302,15 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +/******************************************************************************* + * Extended SQL statement hooks + *******************************************************************************/ -+DefElem * -+sepgsqlGramSecurityItem(char *defname, char *value) -+{ -+ DefElem *n = NULL; -+ -+ if (strcmp(defname, "security_context") == 0) -+ n = makeDefElem(pstrdup(defname), (Node *) makeString(value)); -+ return n; -+} -+ +bool +sepgsqlIsGramSecurityItem(DefElem *defel) +{ + Assert(IsA(defel, DefElem)); + -+ if (defel->defname && strcmp(defel->defname, "security_context") == 0) ++ if (defel->defname && ++ strcmp(defel->defname, SecurityLabelAttributeName) == 0) + return true; ++ + return false; +} + @@ -6333,9 +8319,9 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + if (defel) + { -+ Oid security_id = pgaceSecurityLabelToSid(strVal(defel->arg)); ++ Oid sid = pgaceSecurityLabelToSid(strVal(defel->arg)); + -+ HeapTupleSetSecurity(tuple, security_id); ++ HeapTupleSetSecLabel(tuple, sid); + } +} + @@ -6395,6 +8381,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +sepgsqlGetDatabaseParam(const char *name) +{ + HeapTuple tuple; ++ const char *audit_name; + + tuple = SearchSysCache(DATABASEOID, + ObjectIdGetDatum(MyDatabaseId), 0, 0, 0); @@ -6402,10 +8389,11 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + elog(ERROR, "SELinux: cache lookup failed for database %u", + MyDatabaseId); + -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), ++ audit_name = sepgsqlTupleName(DatabaseRelationId, tuple); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple), + SECCLASS_DB_DATABASE, + DB_DATABASE__GET_PARAM, -+ sepgsqlTupleName(DatabaseRelationId, tuple)); ++ audit_name); + ReleaseSysCache(tuple); +} + @@ -6413,6 +8401,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +sepgsqlSetDatabaseParam(const char *name, char *argstring) +{ + HeapTuple tuple; ++ const char *audit_name; + + tuple = SearchSysCache(DATABASEOID, + ObjectIdGetDatum(MyDatabaseId), 0, 0, 0); @@ -6420,10 +8409,11 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + elog(ERROR, "SELinux: cache lookup failed for database %u", + MyDatabaseId); + -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), ++ audit_name = sepgsqlTupleName(DatabaseRelationId, tuple); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple), + SECCLASS_DB_DATABASE, + DB_DATABASE__SET_PARAM, -+ sepgsqlTupleName(DatabaseRelationId, tuple)); ++ audit_name); + ReleaseSysCache(tuple); +} + @@ -6435,18 +8425,70 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + HeapTuple tuple; + -+ tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); ++ 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) -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), ++ { ++ const char *audit_name ++ = sepgsqlTupleName(RelationRelationId, tuple); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple), + SECCLASS_DB_TABLE, + DB_TABLE__LOCK, -+ sepgsqlTupleName(RelationRelationId, tuple)); ++ 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 + *******************************************************************************/ @@ -6485,16 +8527,21 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +} + +void -+sepgsqlCallFunction(FmgrInfo *finfo, bool with_perm_check) ++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); + @@ -6502,7 +8549,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + /* + * check trusted procedure + */ -+ newcon = sepgsqlClientCreateContext(HeapTupleGetSecurity(tuple), ++ newcon = sepgsqlClientCreateContext(HeapTupleGetSecLabel(tuple), + SECCLASS_PROCESS); + if (strcmp(newcon, sepgsqlGetClientContext()) != 0) + { @@ -6521,32 +8568,51 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + + MemoryContextSwitchTo(oldctx); + -+ if (with_perm_check) -+ { -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), -+ SECCLASS_DB_PROCEDURE, -+ perms, -+ sepgsqlTupleName(ProcedureRelationId, tuple)); -+ } ++ 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 -+sepgsqlCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata) ++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)) -+ { -+ /* -+ * No need to check db_tuple:{select} for a statement trigger -+ */ -+ sepgsqlCallFunction(finfo, false); + return true; -+ } + + if (TRIGGER_FIRED_BY_INSERT(tgdata->tg_event)) + { @@ -6558,9 +8624,9 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + oldtup = tgdata->tg_trigtuple; + if (TRIGGER_FIRED_AFTER(tgdata->tg_event)) + { -+ Oid securityId = HeapTupleGetSecurity(tgdata->tg_newtuple); ++ Oid securityId = HeapTupleGetSecLabel(tgdata->tg_newtuple); + -+ if (HeapTupleGetSecurity(oldtup) != securityId) ++ if (HeapTupleGetSecLabel(oldtup) != securityId) + newtup = tgdata->tg_newtuple; + } + } @@ -6581,8 +8647,29 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + SEPGSQL_PERMS_SELECT, false)) + return false; + -+ sepgsqlCallFunction(finfo, 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; +} + @@ -6596,8 +8683,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + + if (getfilecon_raw(filename, &filecon) < 0) + ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get context of %s", filename))); ++ (errcode_for_file_access(), ++ errmsg("could not access file \"%s\": %m", filename))); + PG_TRY(); + { + sepgsqlComputePermission(sepgsqlGetDatabaseContext(), @@ -6622,20 +8709,24 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +void +sepgsqlLargeObjectCreate(Relation rel, HeapTuple tuple) +{ ++ const char *audit_name; ++ + sepgsqlSetDefaultContext(rel, tuple); + -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), ++ audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple), + SECCLASS_DB_BLOB, + DB_BLOB__CREATE, -+ sepgsqlTupleName(RelationGetRelid(rel), tuple)); ++ audit_name); +} + +void +sepgsqlLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem) +{ -+ Oid security_id = HeapTupleGetSecurity(tuple); ++ Oid security_id = HeapTupleGetSecLabel(tuple); + List *okList = (List *) (*pgaceItem); + ListCell *l; ++ const char *audit_name; + + foreach (l, okList) + { @@ -6643,10 +8734,11 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + return; /* already allowed */ + } + ++ audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple); + sepgsqlClientHasPermission(security_id, + SECCLASS_DB_BLOB, + DB_BLOB__DROP, -+ sepgsqlTupleName(RelationGetRelid(rel), tuple)); ++ audit_name); + + *pgaceItem = lappend_oid(okList, security_id); +} @@ -6689,11 +8781,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + = (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 = HeapTupleGetSecurity(tuple); ++ security_id = HeapTupleGetSecLabel(tuple); + + foreach (l, okList) + { @@ -6702,10 +8795,11 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + } + okList = lappend_oid(okList, security_id); + ++ audit_name = sepgsqlTupleName(LargeObjectRelationId, tuple); + sepgsqlClientHasPermission(security_id, + SECCLASS_DB_BLOB, + perms, -+ sepgsqlTupleName(RelationGetRelid(rel), tuple)); ++ audit_name); + skip: + ; + } @@ -6750,12 +8844,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + security_context_t tcontext; + security_class_t tclass -+ = sepgsqlProperFileObjectClass(fdesc, filename); ++ = sepgsqlFileObjectClass(fdesc, filename); + + if (fgetfilecon_raw(fdesc, &tcontext) < 0) + ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get context of %s", filename))); ++ (errcode_for_file_access(), ++ errmsg("could not get security context \"%s\": %m", filename))); + PG_TRY(); + { + sepgsqlComputePermission(sepgsqlGetClientContext(), @@ -6781,12 +8875,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + security_context_t tcontext; + security_class_t tclass -+ = sepgsqlProperFileObjectClass(fdesc, filename); ++ = sepgsqlFileObjectClass(fdesc, filename); + + if (fgetfilecon_raw(fdesc, &tcontext) < 0) + ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get context of %s", filename))); ++ (errcode_for_file_access(), ++ errmsg("could not security context \"%s\": %m", filename))); + PG_TRY(); + { + sepgsqlComputePermission(sepgsqlGetClientContext(), @@ -6810,29 +8904,36 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +void +sepgsqlLargeObjectGetSecurity(Relation rel, HeapTuple tuple) +{ -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), ++ const char *audit_name ++ = sepgsqlTupleName(LargeObjectRelationId, tuple); ++ ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple), + SECCLASS_DB_BLOB, + DB_BLOB__GETATTR, -+ sepgsqlTupleName(RelationGetRelid(rel), tuple)); ++ audit_name); +} + +void +sepgsqlLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup) +{ -+ if (HeapTupleGetSecurity(newtup) == HeapTupleGetSecurity(oldtup)) ++ const char *audit_name; ++ ++ if (HeapTupleGetSecLabel(newtup) == HeapTupleGetSecLabel(oldtup)) + return; + -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(oldtup), ++ audit_name = sepgsqlTupleName(LargeObjectRelationId, oldtup); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(oldtup), + SECCLASS_DB_BLOB, + DB_BLOB__SETATTR | DB_BLOB__RELABELFROM, -+ sepgsqlTupleName(RelationGetRelid(rel), oldtup)); ++ audit_name); + /* + * check db_blob:{setattr relabelto} + */ -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(newtup), ++ audit_name = sepgsqlTupleName(LargeObjectRelationId, newtup); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(newtup), + SECCLASS_DB_BLOB, + DB_BLOB__RELABELTO, -+ sepgsqlTupleName(RelationGetRelid(rel), newtup)); ++ audit_name); +} + +/******************************************************************************* @@ -6844,7 +8945,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot) +{ + HeapTuple tuple; -+ uint32 perms = scan->pgaceTuplePerms; ++ uint32 perms = (scan->pgaceTuplePerms & SEPGSQL_PERMS_MASK); + + if (perms == 0) + return true; @@ -6884,6 +8985,29 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +/******************************************************************************* + * 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) +{ @@ -6935,7 +9059,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +} + +/* -+ * sepgsqlCheckValidateSecurityLabel() checks whether the given ++ * sepgsqlCheckValidSecurityLabel() checks whether the given + * security context is valid on the current working security + * policy, or not. + * If it's invalid, sepgsqlUnlabeledSecurityLabel() is invoked @@ -6990,7 +9114,9 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + elog(ERROR, "SELinux: cache lookup failed for relation %u", + SecurityRelationId); + -+ table_context = pgaceLookupSecurityLabel(HeapTupleGetSecurity(tuple)); ++ table_context = pgaceLookupSecurityLabel(HeapTupleGetSecLabel(tuple)); ++ if (!table_context || !pgaceCheckValidSecurityLabel(table_context)) ++ table_context = pgaceUnlabeledSecurityLabel(); + + tuple_context = sepgsqlComputeCreateContext(sepgsqlGetServerContext(), + table_context, SECCLASS_DB_TUPLE); @@ -7063,15 +9189,19 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + /* + * default context for no explicit labeled tuple + */ -+ if (HeapTupleGetSecurity(tuple) == InvalidOid) ++ if (!OidIsValid(HeapTupleGetSecLabel(tuple))) + { -+ if (HeapTupleHasSecurity(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: not allowed to insert into " ++ errmsg("SELinux: unable to insert " + "pg_largeobject.security_context"))); + + if (isTrustedRelation(rel, is_internal)) @@ -7088,46 +9218,52 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +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 (HeapTupleGetSecurity(newtup) == InvalidOid) ++ if (!OidIsValid(HeapTupleGetSecLabel(newtup))) + { -+ Oid securityId = HeapTupleGetSecurity(oldtup); ++ /* ++ * If user does not specify new security context ++ * explicitly, it preserves a security context of ++ * older tuple. ++ */ ++ Oid sid = HeapTupleGetSecLabel(oldtup); + -+ if (HeapTupleHasSecurity(newtup)) -+ HeapTupleSetSecurity(newtup, securityId); ++ if (HeapTupleHasSecLabel(newtup)) ++ HeapTupleSetSecLabel(newtup, sid); + } + else if (!is_internal && RelationGetRelid(rel) == LargeObjectRelationId) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: not allowed to update " ++ errmsg("SELinux: unable to update " + "pg_largeobject.security_context"))); + + if (isTrustedRelation(rel, is_internal)) + return true; + -+ if (is_internal) -+ { -+ perms = SEPGSQL_PERMS_UPDATE; -+ if (HeapTupleGetSecurity(newtup) != HeapTupleGetSecurity(oldtup)) -+ perms |= SEPGSQL_PERMS_RELABELFROM; -+ else if (with_returning) -+ perms |= SEPGSQL_PERMS_SELECT; -+ rc = sepgsqlCheckTuplePerms(rel, oldtup, NULL, perms, is_internal); -+ if (!rc) -+ goto out; -+ } ++ if (HeapTupleGetSecLabel(newtup) != HeapTupleGetSecLabel(oldtup) || ++ sepgsqlTupleObjectClass(relid, newtup) != sepgsqlTupleObjectClass(relid, oldtup)) ++ relabel = true; + -+ if (HeapTupleGetSecurity(newtup) != HeapTupleGetSecurity(oldtup)) ++ 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, oldtup, perms, is_internal); ++ rc = sepgsqlCheckTuplePerms(rel, newtup, NULL, perms, is_internal); + } + out: + heap_freetuple(oldtup); @@ -7142,15 +9278,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + uint32 perms = SEPGSQL_PERMS_DELETE; + bool rc; + -+ if (!is_internal) -+ return true; -+ + if (isTrustedRelation(rel, is_internal)) + return true; + + oldtup = getHeapTupleFromItemPointer(rel, otid); -+ if (with_returning) -+ perms |= SEPGSQL_PERMS_SELECT; + rc = sepgsqlCheckTuplePerms(rel, oldtup, NULL, perms, is_internal); + heap_freetuple(oldtup); + @@ -7158,8 +9289,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +} diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/security/sepgsql/permissions.c --- base/src/backend/security/sepgsql/permissions.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/permissions.c 2008-11-05 11:06:00.000000000 +0900 -@@ -0,0 +1,622 @@ ++++ sepgsql/src/backend/security/sepgsql/permissions.c 2009-01-22 14:28:10.000000000 +0900 +@@ -0,0 +1,794 @@ + +/* + * src/backend/security/sepgsql/permissions.c @@ -7174,146 +9305,104 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ +#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" + +#include + -+static access_vector_t -+sepgsql_perms_to_common_perms(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 -+sepgsql_perms_to_tuple_perms(uint32 perms) -+{ -+ 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; -+} ++/* ++ * It can be configured via a GUC variable to toggle ++ * row-level access controls. ++ */ ++bool sepostgresql_row_level = true; + ++/* ++ * 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 * 3]; ++ static char buffer[NAMEDATALEN * 2 + 10]; + + switch (relid) + { -+ case AttributeRelationId: ++ 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) + { -+ Form_pg_attribute attForm -+ = (Form_pg_attribute) GETSTRUCT(tuple); -+ -+ if (!IsBootstrapProcessingMode()) -+ { -+ HeapTuple exttup = SearchSysCache(RELOID, -+ ObjectIdGetDatum -+ (attForm->attrelid), -+ 0, 0, 0); -+ -+ if (HeapTupleIsValid(exttup)) -+ { -+ snprintf(buffer, sizeof(buffer), "%s.%s", -+ NameStr(((Form_pg_class) GETSTRUCT(exttup))->relname), -+ NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname)); -+ ReleaseSysCache(exttup); -+ break; -+ } -+ } -+ snprintf(buffer, sizeof(buffer), "%s", -+ NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname)); -+ break; ++ snprintf(buffer, sizeof(buffer), "%s.%s", ++ relname, NameStr(attForm->attname)); ++ pfree(relname); ++ return buffer; + } -+ case AuthIdRelationId: -+ snprintf(buffer, sizeof(buffer), "%s", -+ NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname)); -+ break; ++ } ++ return NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname); + -+ case RelationRelationId: -+ snprintf(buffer, sizeof(buffer), "%s", -+ NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname)); -+ break; ++ case ProcedureRelationId: ++ return NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname); + -+ case DatabaseRelationId: -+ snprintf(buffer, sizeof(buffer), "%s", -+ NameStr(((Form_pg_database) GETSTRUCT(tuple))->datname)); -+ break; -+ -+ case LargeObjectRelationId: -+ snprintf(buffer, sizeof(buffer), "loid:%u", -+ ((Form_pg_largeobject) GETSTRUCT(tuple))->loid); -+ break; -+ -+ case ProcedureRelationId: -+ snprintf(buffer, sizeof(buffer), "%s", -+ NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname)); -+ break; -+ -+ case TriggerRelationId: -+ snprintf(buffer, sizeof(buffer), "%s", -+ NameStr(((Form_pg_trigger) GETSTRUCT(tuple))->tgname)); -+ break; -+ -+ case TypeRelationId: -+ snprintf(buffer, sizeof(buffer), "pg_type::%s", -+ NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname)); -+ break; -+ default: -+ /* -+ * this tuple has no name -+ */ -+ return NULL; ++ case LargeObjectRelationId: ++ snprintf(buffer, sizeof(buffer), "loid:%u", ++ ((Form_pg_largeobject) GETSTRUCT(tuple))->loid); ++ return buffer; + } -+ return buffer; ++ return NULL; /* No tuple name for audit record */ +} + +/* -+ * sepgsqlProperFileObjectClass ++ * sepgsqlFileObjectClass + * + * It returns proper object class of filesystem object already opened. + * It is necessary to check privileges voluntarily. + */ +security_class_t -+sepgsqlProperFileObjectClass(int fdesc, const char *filename) ++sepgsqlFileObjectClass(int fdesc, const char *filename) +{ + struct stat stbuf; + + if (fstat(fdesc, &stbuf) != 0) + ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get file status of %s", filename))); ++ (errcode_for_file_access(), ++ errmsg("could not stat file \"%s\": %m", filename))); + + if (S_ISDIR(stbuf.st_mode)) + return SECCLASS_DIR; @@ -7332,6 +9421,49 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ +} + +/* ++ * 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->attrelid == TypeRelationId || ++ attForm->attrelid == ProcedureRelationId || ++ attForm->attrelid == AttributeRelationId || ++ attForm->attrelid == RelationRelationId || ++ get_rel_relkind(attForm->attrelid) == 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 @@ -7347,61 +9479,131 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + * Thus, checks for some of system catalog need to modify given permission + * set at checkTuplePermsXXXX() functions. + */ -+ -+static void -+checkTuplePermsAttribute(HeapTuple tuple, HeapTuple oldtup, -+ access_vector_t *p_perms, -+ security_class_t *p_tclass) ++static access_vector_t ++sepgsqlPermsToCommonAv(uint32 perms) +{ -+ Form_pg_attribute attForm, oldForm; -+ HeapTuple reltup; ++ access_vector_t result = 0; + -+ attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ switch (attForm->attrelid) -+ { -+ case TypeRelationId: -+ case ProcedureRelationId: -+ case AttributeRelationId: -+ case RelationRelationId: -+ /* -+ * those are pure relation -+ */ -+ break; -+ default: -+ reltup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(attForm->attrelid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(reltup)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", -+ attForm->attrelid); -+ if (RELKIND_RELATION != -+ ((Form_pg_class) GETSTRUCT(reltup))->relkind) -+ { -+ *p_tclass = SECCLASS_DB_TUPLE; -+ *p_perms = sepgsql_perms_to_tuple_perms(*p_perms); -+ ReleaseSysCache(reltup); -+ return; -+ } -+ ReleaseSysCache(reltup); -+ break; -+ } -+ *p_tclass = SECCLASS_DB_COLUMN; -+ *p_perms = sepgsql_perms_to_common_perms(*p_perms); -+ if (HeapTupleIsValid(oldtup)) -+ { -+ oldForm = (Form_pg_attribute) GETSTRUCT(oldtup); ++ 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); + -+ if (oldForm->attisdropped != true && attForm->attisdropped == true) -+ *p_perms |= DB_COLUMN__DROP; -+ } ++ return result; +} + -+static void -+checkTuplePermsLargeObject(HeapTuple tuple, HeapTuple oldtup, -+ access_vector_t *p_perms, -+ security_class_t *p_tclass) ++static access_vector_t ++sepgsqlPermsToDatabaseAv(uint32 perms, HeapTuple tuple, HeapTuple newtup) +{ -+ access_vector_t perms; ++ 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 @@ -7409,6 +9611,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + * 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, @@ -7417,166 +9623,277 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + * So, we assume any INSERT means db_blob:{create}, any DELETE means + * db_blob:{drop}. + */ -+ perms = sepgsql_perms_to_common_perms(*p_perms); -+ perms |= (*p_perms & SEPGSQL_PERMS_INSERT ? DB_BLOB__WRITE : 0); -+ perms |= (*p_perms & SEPGSQL_PERMS_DELETE ? DB_BLOB__WRITE : 0); -+ perms |= (*p_perms & SEPGSQL_PERMS_READ ? DB_BLOB__READ : 0); -+ perms |= (*p_perms & SEPGSQL_PERMS_WRITE ? DB_BLOB__WRITE : 0); -+ -+ *p_tclass = SECCLASS_DB_BLOB; -+ *p_perms = perms; -+} -+ -+static void -+checkTuplePermsProcedure(HeapTuple tuple, HeapTuple oldtup, -+ access_vector_t *p_perms, -+ security_class_t *p_tclass) -+{ -+ access_vector_t perms = sepgsql_perms_to_common_perms(*p_perms); -+ Form_pg_proc procForm = (Form_pg_proc) GETSTRUCT(tuple); -+ -+ if (procForm->prolang == ClanguageId) ++ result |= (perms & SEPGSQL_PERMS_INSERT ? DB_BLOB__WRITE : 0); ++ if (perms & SEPGSQL_PERMS_UPDATE) + { -+ Datum oldbin, newbin; -+ bool isnull, verify = false; ++ result |= DB_BLOB__WRITE; + -+ newbin = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull); -+ if (!isnull) -+ { -+ if (perms & DB_PROCEDURE__CREATE) -+ { -+ verify = true; -+ } -+ else if (HeapTupleIsValid(oldtup)) -+ { -+ oldbin = SysCacheGetAttr(PROCOID, oldtup, -+ Anum_pg_proc_probin, &isnull); -+ if (isnull || -+ DatumGetBool(DirectFunctionCall2(textne, oldbin, newbin))) -+ verify = true; -+ } -+ -+ if (verify) -+ { -+ char *file_name; -+ security_context_t file_context; -+ -+ /* -+ * <-- database:module_install --> -+ */ -+ sepgsqlClientHasPermission(sepgsqlGetDatabaseSecurityId(), -+ SECCLASS_DB_DATABASE, -+ DB_DATABASE__INSTALL_MODULE, -+ NULL); -+ -+ /* -+ * <-- database:module_install --> -+ */ -+ file_name = DatumGetCString(DirectFunctionCall1(textout, newbin)); -+ file_name = expand_dynamic_library_name(file_name); -+ if (getfilecon_raw(file_name, &file_context) < 0) -+ ereport(ERROR, -+ (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: could not get context of %s", -+ file_name))); -+ PG_TRY(); -+ { -+ sepgsqlComputePermission(sepgsqlGetClientContext(), -+ file_context, -+ SECCLASS_DB_DATABASE, -+ DB_DATABASE__INSTALL_MODULE, -+ file_name); -+ } -+ PG_CATCH(); -+ { -+ freecon(file_context); -+ PG_RE_THROW(); -+ } -+ PG_END_TRY(); -+ freecon(file_context); -+ } -+ } ++ if (((Form_pg_largeobject) GETSTRUCT(tuple))->loid != ++ ((Form_pg_largeobject) GETSTRUCT(newtup))->loid) ++ result |= (DB_BLOB__CREATE | DB_BLOB__DROP); + } -+ *p_perms = perms; -+ *p_tclass = SECCLASS_DB_PROCEDURE; ++ 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 -+checkTuplePermsRelation(HeapTuple tuple, HeapTuple oldtup, -+ access_vector_t *p_perms, -+ security_class_t *p_tclass) ++checkProcedureInstall(Oid proc_oid) +{ -+ Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); ++ if (!OidIsValid(proc_oid)) ++ return; + -+ if (classForm->relkind == RELKIND_RELATION) ++ if (IsBootstrapProcessingMode()) + { -+ *p_tclass = SECCLASS_DB_TABLE; -+ *p_perms = sepgsql_perms_to_common_perms(*p_perms); ++ /* ++ * 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 + { -+ *p_tclass = SECCLASS_DB_TUPLE; -+ *p_perms = sepgsql_perms_to_tuple_perms(*p_perms); ++ 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, amgetmulti, 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 oldtup, ++sepgsqlCheckTuplePerms(Relation rel, HeapTuple tuple, HeapTuple newtup, + uint32 perms, bool abort) +{ + security_class_t tclass; -+ bool rc = true; ++ access_vector_t av = 0; ++ bool rc = true; + -+ Assert(tuple != NULL); ++ Assert(HeapTupleIsValid(tuple)); + -+ switch (RelationGetRelid(rel)) ++ if ((perms & (SEPGSQL_PERMS_INSERT | SEPGSQL_PERMS_UPDATE)) != 0) ++ sepgsqlCheckProcedureInstall(rel, tuple, newtup); ++ ++ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple); ++ ++ switch (tclass) + { -+ case DatabaseRelationId: /* pg_datbase */ -+ perms = sepgsql_perms_to_common_perms(perms); -+ tclass = SECCLASS_DB_DATABASE; ++ case SECCLASS_DB_DATABASE: ++ av = sepgsqlPermsToDatabaseAv(perms, tuple, newtup); + break; + -+ case RelationRelationId: /* pg_class */ -+ checkTuplePermsRelation(tuple, oldtup, &perms, &tclass); ++ case SECCLASS_DB_TABLE: ++ av = sepgsqlPermsToTableAv(perms, tuple, newtup); + break; + -+ case AttributeRelationId: /* pg_attribute */ -+ checkTuplePermsAttribute(tuple, oldtup, &perms, &tclass); ++ case SECCLASS_DB_PROCEDURE: ++ av = sepgsqlPermsToProcedureAv(perms, tuple, newtup); + break; + -+ case ProcedureRelationId: /* pg_proc */ -+ checkTuplePermsProcedure(tuple, oldtup, &perms, &tclass); ++ case SECCLASS_DB_COLUMN: ++ av = sepgsqlPermsToColumnAv(perms, tuple, newtup); + break; + -+ case LargeObjectRelationId: /* pg_largeobject */ -+ checkTuplePermsLargeObject(tuple, oldtup, &perms, &tclass); ++ case SECCLASS_DB_BLOB: ++ av = sepgsqlPermsToBlobAv(perms, tuple, newtup); + break; + -+ default: -+ perms = sepgsql_perms_to_tuple_perms(perms); -+ tclass = SECCLASS_DB_TUPLE; ++ default: /* SECCLASS_DB_TUPLE */ ++ if (sepostgresql_row_level) ++ av = sepgsqlPermsToTupleAv(perms, tuple, newtup); + break; + } + -+ if (perms) ++ if (av) + { -+ const char *objname = sepgsqlTupleName(RelationGetRelid(rel), tuple); ++ const char *audit_name ++ = sepgsqlTupleName(RelationGetRelid(rel), tuple); + + if (abort) + { -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), -+ tclass, perms, objname); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple), ++ tclass, av, audit_name); + } + else + { -+ rc = sepgsqlClientHasPermissionNoAbort(HeapTupleGetSecurity(tuple), -+ tclass, perms, objname); ++ 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, @@ -7585,112 +9902,131 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + * However, we have several exception for some of system catalog. It come from + * TYPE_TRANSITION rules in the security policy. + */ -+ -+static void -+setDefaultContextDatabase(Relation rel, HeapTuple tuple) ++static Oid ++sepgsqlDefaultDatabaseContext(Relation rel, HeapTuple tuple) +{ -+ Oid security_id; + security_context_t newcon; + + newcon = sepgsqlComputeCreateContext(sepgsqlGetClientContext(), + sepgsqlGetClientContext(), + SECCLASS_DB_DATABASE); -+ security_id = pgaceSecurityLabelToSid(newcon); -+ HeapTupleSetSecurity(tuple, security_id); ++ return pgaceSecurityLabelToSid(newcon); +} + -+static void -+setDefaultContextRelation(Relation rel, HeapTuple tuple) ++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; + -+ tblsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), -+ SECCLASS_DB_TABLE); -+ HeapTupleSetSecurity(tuple, tblsid); -+} -+ -+static void -+setDefaultContextAttribute(Relation rel, HeapTuple tuple) -+{ -+ HeapTuple reltup; -+ Oid security_id; -+ Form_pg_class clsForm; -+ Form_pg_attribute attForm -+ = (Form_pg_attribute) GETSTRUCT(tuple); -+ -+ switch (attForm->attrelid) ++ if (IsBootstrapProcessingMode() && ++ (RelationGetRelid(rel) == TypeRelationId || ++ RelationGetRelid(rel) == ProcedureRelationId || ++ RelationGetRelid(rel) == AttributeRelationId || ++ RelationGetRelid(rel) == RelationRelationId)) + { -+ case TypeRelationId: -+ case ProcedureRelationId: -+ case AttributeRelationId: -+ case RelationRelationId: + /* -+ * we cannot touch these relations at very early phase in bootstrap ++ * We cannot access relation caches on very early phase ++ * in bootstrap, so it assumes tables has default security ++ * context and unlabeled by initdb. + */ -+ if (IsBootstrapProcessingMode()) -+ { -+ Oid security_id; -+ -+ security_id = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), -+ SECCLASS_DB_TABLE); -+ HeapTupleSetSecurity(tuple, security_id); -+ break; -+ } -+ default: -+ reltup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(attForm->attrelid), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(reltup)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", -+ attForm->attrelid); -+ clsForm = (Form_pg_class) GETSTRUCT(reltup); -+ -+ security_id = sepgsqlClientCreateSid(HeapTupleGetSecurity(reltup), -+ (clsForm->relkind == RELKIND_RELATION -+ ? SECCLASS_DB_COLUMN -+ : SECCLASS_DB_TUPLE)); -+ HeapTupleSetSecurity(tuple, security_id); -+ -+ ReleaseSysCache(reltup); -+ break; ++ tblsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), ++ SECCLASS_DB_TABLE); + } -+ return; ++ 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 void -+setDefaultContextProcedure(Relation rel, HeapTuple tuple) -+{ -+ Oid security_id; -+ -+ security_id = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), -+ SECCLASS_DB_PROCEDURE); -+ HeapTupleSetSecurity(tuple, security_id); -+} -+ -+static void -+setDefaultContextLargeObject(Relation rel, HeapTuple tuple) ++static Oid ++sepgsqlDefaultBlobContext(Relation rel, HeapTuple tuple) +{ + /* + * NOTE: -+ * A new tuple to be inserted into pg_largeobject inheris -+ * security context of tuple with same large object id. -+ * We can scan it with SnapshotNow because lo_create invokes -+ * CommandCounterIncrement() just after create a new large -+ * object. ++ * 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 no page found, it means this action is to insert the -+ * first page, or user run INSERT INTO ... statement with -+ * multiple tuples with same loid. -+ * However, these newly inserted tuples are labeled by -+ * TYPE_TRANSITION rules in both cases. So, there are -+ * no differences. ++ * 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 security_id = InvalidOid; ++ Oid newsid = InvalidOid; + + ScanKeyInit(&skey, + Anum_pg_largeobject_loid, @@ -7701,99 +10037,64 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + SnapshotNow, 1, &skey); + while ((lotup = systable_getnext(scan)) != NULL) + { -+ security_id = HeapTupleGetSecurity(lotup); -+ if (security_id != InvalidOid) ++ newsid = HeapTupleGetSecLabel(lotup); ++ if (OidIsValid(newsid)) + break; + } + systable_endscan(scan); + -+ if (security_id == InvalidOid) ++ if (!OidIsValid(newsid)) + { -+ security_id = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), -+ SECCLASS_DB_BLOB); ++ newsid = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), ++ SECCLASS_DB_BLOB); + } -+ HeapTupleSetSecurity(tuple, security_id); ++ ++ return newsid; +} + +void +sepgsqlSetDefaultContext(Relation rel, HeapTuple tuple) +{ -+ HeapTuple reltup; -+ Oid security_id; ++ security_class_t tclass; ++ Oid newsid; + -+ switch (RelationGetRelid(rel)) ++ Assert(HeapTupleHasSecLabel(tuple)); ++ tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple); ++ ++ switch (tclass) + { -+ case DatabaseRelationId: -+ setDefaultContextDatabase(rel, tuple); -+ return; -+ -+ case RelationRelationId: -+ { -+ Form_pg_class clsForm -+ = (Form_pg_class) GETSTRUCT(tuple); -+ -+ if (clsForm->relkind == RELKIND_RELATION) -+ { -+ setDefaultContextRelation(rel, tuple); -+ return; -+ } -+ } ++ case SECCLASS_DB_DATABASE: ++ newsid = sepgsqlDefaultDatabaseContext(rel, tuple); + break; -+ -+ case AttributeRelationId: -+ setDefaultContextAttribute(rel, tuple); -+ return; -+ -+ case ProcedureRelationId: -+ setDefaultContextProcedure(rel, tuple); -+ return; -+ -+ case LargeObjectRelationId: -+ setDefaultContextLargeObject(rel, tuple); -+ return; -+ -+ case TypeRelationId: -+ if (IsBootstrapProcessingMode()) -+ { -+ /* -+ * we cannot touch system cache in very early phase -+ */ -+ security_id = sepgsqlClientCreateSid(sepgsqlGetDatabaseSecurityId(), -+ SECCLASS_DB_TABLE); -+ HeapTupleSetSecurity(tuple, security_id); -+ -+ return; -+ } ++ 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; + } -+ /* -+ * normal or user defined relation -+ */ -+ reltup = SearchSysCache(RELOID, -+ ObjectIdGetDatum(RelationGetRelid(rel)), -+ 0, 0, 0); -+ if (!HeapTupleIsValid(reltup)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", -+ RelationGetRelid(rel)); + -+ security_id = sepgsqlClientCreateSid(HeapTupleGetSecurity(reltup), -+ SECCLASS_DB_TUPLE); -+ HeapTupleSetSecurity(tuple, security_id); -+ -+ ReleaseSysCache(reltup); ++ HeapTupleSetSecLabel(tuple, newsid); +} diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/security/sepgsql/proxy.c --- base/src/backend/security/sepgsql/proxy.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/proxy.c 2008-10-31 17:01:56.000000000 +0900 -@@ -0,0 +1,1465 @@ ++++ sepgsql/src/backend/security/sepgsql/proxy.c 2009-01-23 13:07:12.000000000 +0900 +@@ -0,0 +1,1074 @@ +/* + * src/backend/security/sepgsql/proxy.c -+ * proxy routines to pick up all appeared columns, functions, ... -+ * within given queries, and apply mandatory access controls. ++ * Proxying the given Query trees via SE-PostgreSQL + * -+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group ++ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California -+ * + */ +#include "postgres.h" + @@ -7809,6 +10110,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +#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" @@ -7822,48 +10124,34 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +#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" + +/* -+ * queryStack -+ * -+ * This structure represents a hierarchical relationshipt -+ * between subqueries. When a Var node has positive varlevelsup, -+ * it refers upper level Query structure using the chain of -+ * queryStack. -+ */ -+typedef struct queryStack -+{ -+ struct queryStack *parent; -+ Query *query; -+} queryStack; -+ -+/* + * sepgsqlWalkerContext + * + * This structure holds a context during analyzing a given query. + * selist is a list of SEvalItemXXX objects to enumerate appared -+ * tables, columns and functions. It is evaluated later, just -+ * before executing query. ++ * 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 +{ -+ List *selist; /* List of SEvalItem */ -+ -+ struct queryStack *qstack; -+ -+ bool is_internal_use; ++ struct sepgsqlWalkerContext *parent; ++ Query *query; /* Query structure of current layer */ ++ List *selist; /* list of SEvalItemXXX */ ++ bool is_internal_use; +} sepgsqlWalkerContext; + -+/* static definitions for proxy functions */ -+static void proxyRteSubQuery(sepgsqlWalkerContext *swc, Query *query); ++#define seitem_index_to_attno(index) \ ++ ((index) + FirstLowInvalidHeapAttributeNumber + 1) ++#define seitem_attno_to_index(attno) \ ++ ((attno) - FirstLowInvalidHeapAttributeNumber - 1) + -+static bool sepgsqlExprWalker(Node *node, sepgsqlWalkerContext *swc); -+ -+static void execVerifyQuery(List *selist); + +/* + * addEvalRelation @@ -7878,50 +10166,48 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +static List * +addEvalRelation(List *selist, Oid relid, bool inh, uint32 perms) +{ -+ SEvalItemRelation *ser; ++ SelinuxEvalItem *seitem; ++ Form_pg_class relForm; ++ HeapTuple tuple; ++ ListCell *l; + -+ ListCell *l; -+ -+ foreach(l, selist) ++ foreach (l, selist) + { -+ ser = (SEvalItemRelation *) lfirst(l); -+ if (IsA(ser, SEvalItemRelation) -+ && ser->relid == relid -+ && ser->inh == inh) ++ seitem = (SelinuxEvalItem *) lfirst(l); ++ Assert(IsA(seitem, SelinuxEvalItem)); ++ ++ if (seitem->relid == relid && seitem->inh == inh) + { -+ ser->perms |= perms; ++ seitem->relperms |= perms; + return selist; + } + } -+ /* -+ * not found -+ */ -+ ser = makeNode(SEvalItemRelation); -+ ser->perms = perms; -+ ser->relid = relid; -+ ser->inh = inh; + -+ return lappend(selist, ser); ++ /* 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); -+ rte->pgaceTuplePerms |= -+ (perms & DB_TABLE__INSERT ? SEPGSQL_PERMS_INSERT : 0); -+ rte->pgaceTuplePerms |= -+ (perms & DB_TABLE__UPDATE ? SEPGSQL_PERMS_UPDATE : 0); -+ rte->pgaceTuplePerms |= -+ (perms & DB_TABLE__DELETE ? SEPGSQL_PERMS_DELETE : 0); -+ -+ /* -+ * for 'pg_largeobject' -+ */ -+ if (rte->relid == LargeObjectRelationId && (perms & DB_TABLE__DELETE)) -+ rte->pgaceTuplePerms |= SEPGSQL_PERMS_WRITE; ++ rte->pgaceTuplePerms |= (perms & DB_TABLE__SELECT ? SEPGSQL_PERMS_SELECT : 0); + + return addEvalRelation(selist, rte->relid, rte->inh, perms); +} @@ -7939,131 +10225,118 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +static List * +addEvalAttribute(List *selist, Oid relid, bool inh, AttrNumber attno, uint32 perms) +{ -+ SEvalItemAttribute *sea; ++ SelinuxEvalItem *seitem; ++ Form_pg_class relForm; ++ HeapTuple tuple; ++ ListCell *l; ++ int index = seitem_attno_to_index(attno); + -+ ListCell *l; -+ -+ foreach(l, selist) ++ foreach (l, selist) + { -+ sea = (SEvalItemAttribute *) lfirst(l); -+ if (IsA(sea, SEvalItemAttribute) -+ && sea->relid == relid -+ && sea->inh == inh -+ && sea->attno == attno) ++ seitem = (SelinuxEvalItem *) lfirst(l); ++ Assert(IsA(seitem, SelinuxEvalItem)); ++ ++ if (seitem->relid == relid && seitem->inh == inh) + { -+ sea->perms |= perms; ++ 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 -+ */ -+ sea = makeNode(SEvalItemAttribute); -+ sea->perms = perms; -+ sea->relid = relid; -+ sea->inh = inh; -+ sea->attno = attno; + -+ return lappend(selist, sea); ++ /* 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 t_perms = 0; ++ 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); + + /* -+ * for table:{ ... } permission ++ * Special care for pg_largeobject.data + */ -+ t_perms |= (perms & DB_COLUMN__USE ? DB_TABLE__USE : 0); -+ t_perms |= (perms & DB_COLUMN__SELECT ? DB_TABLE__SELECT : 0); -+ t_perms |= (perms & DB_COLUMN__INSERT ? DB_TABLE__INSERT : 0); -+ t_perms |= (perms & DB_COLUMN__UPDATE ? DB_TABLE__UPDATE : 0); -+ selist = addEvalRelationRTE(selist, rte, t_perms); -+ -+ /* -+ * for 'security_context' -+ */ -+ if (attno == SecurityAttributeNumber -+ && (perms & (DB_COLUMN__UPDATE | DB_COLUMN__INSERT))) -+ rte->pgaceTuplePerms |= SEPGSQL_PERMS_RELABELFROM; -+ -+ /* -+ * for 'pg_largeobject' -+ */ -+ if (rte->relid == LargeObjectRelationId) -+ { -+ if ((perms & DB_COLUMN__SELECT) && attno == Anum_pg_largeobject_data) -+ rte->pgaceTuplePerms |= SEPGSQL_PERMS_READ; -+ if ((perms & DB_COLUMN__UPDATE) && attno == Anum_pg_largeobject_data) -+ rte->pgaceTuplePerms |= SEPGSQL_PERMS_WRITE; -+ } ++ 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); +} + +/* -+ * addEvalPgProc -+ * -+ * This function adds a given procedure into selist, if it is not -+ * contained yet. -+ */ -+static List * -+addEvalPgProc(List *selist, Oid funcid, uint32 perms) -+{ -+ SEvalItemProcedure *sep; -+ -+ ListCell *l; -+ -+ foreach(l, selist) -+ { -+ sep = (SEvalItemProcedure *) lfirst(l); -+ if (IsA(sep, SEvalItemProcedure) -+ && sep->funcid == funcid) -+ { -+ sep->perms |= perms; -+ return selist; -+ } -+ } -+ /* -+ * not found -+ */ -+ sep = makeNode(SEvalItemProcedure); -+ sep->perms = perms; -+ sep->funcid = funcid; -+ -+ return lappend(selist, sep); -+} -+ -+/* + * addEvalForeignKeyConstraint + * + * This function add special case handling for PK/FK constraints. + * invoke trigger function requires to access rights for all attribute + * + */ -+static bool -+triggerIsForeignKeyConstraint(Form_pg_trigger trigger) -+{ -+ switch (trigger->tgfoid) -+ { -+ case F_RI_FKEY_CHECK_INS: -+ case F_RI_FKEY_CHECK_UPD: -+ case F_RI_FKEY_CASCADE_DEL: -+ case F_RI_FKEY_CASCADE_UPD: -+ case F_RI_FKEY_RESTRICT_DEL: -+ case F_RI_FKEY_RESTRICT_UPD: -+ case F_RI_FKEY_SETNULL_DEL: -+ case F_RI_FKEY_SETNULL_UPD: -+ case F_RI_FKEY_SETDEFAULT_DEL: -+ case F_RI_FKEY_SETDEFAULT_UPD: -+ case F_RI_FKEY_NOACTION_DEL: -+ case F_RI_FKEY_NOACTION_UPD: -+ return true; -+ } -+ return false; -+} -+ +static List * +addEvalForeignKeyConstraint(List *selist, Form_pg_trigger trigger) +{ @@ -8109,7 +10382,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +} + +/* -+ * addEvalTriggerAccess ++ * addEvalTriggerFunction + * + * This function adds needed items into selist, to execute a trigger + * function. At least, it requires permission set to execute a function @@ -8117,17 +10390,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + * because whole of a tuple is delivered to trigger functions. + */ +static List * -+addEvalTriggerAccess(List *selist, Oid relid, bool is_inh, int cmdType) ++addEvalTriggerFunction(List *selist, Oid relid, int cmdType) +{ + Relation rel; + SysScanDesc scan; + ScanKeyData skey; + HeapTuple tuple; -+ bool checked = false; -+ -+ Assert(cmdType == CMD_INSERT -+ || cmdType == CMD_UPDATE -+ || cmdType == CMD_DELETE); + + rel = heap_open(TriggerRelationId, AccessShareLock); + ScanKeyInit(&skey, @@ -8138,6 +10406,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + 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 @@ -8152,12 +10422,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + continue; + + /* -+ * add db_procedure:{execute} permission -+ */ -+ selist = addEvalPgProc(selist, trigForm->tgfoid, -+ DB_PROCEDURE__EXECUTE); -+ -+ /* + * per STATEMENT trigger cannot refer whole of a tuple + */ + if (!TRIGGER_FOR_ROW(trigForm->tgtype)) @@ -8170,354 +10434,184 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + TRIGGER_FOR_INSERT(trigForm->tgtype)) + continue; + -+ if (!checked) -+ { -+ HeapTuple reltup; -+ Form_pg_class classForm; ++ reltup = SearchSysCache(RELOID, ++ ObjectIdGetDatum(relid), ++ 0, 0, 0); ++ relForm = (Form_pg_class) GETSTRUCT(reltup); + -+ reltup = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); -+ classForm = (Form_pg_class) GETSTRUCT(reltup); ++ selist = addEvalRelation(selist, relid, false, DB_TABLE__SELECT); + -+ selist = addEvalRelation(selist, relid, false, DB_TABLE__SELECT); -+ -+ if (triggerIsForeignKeyConstraint(trigForm)) -+ selist = addEvalForeignKeyConstraint(selist, trigForm); -+ else -+ selist = addEvalAttribute(selist, relid, false, -+ 0, DB_COLUMN__SELECT); -+ ReleaseSysCache(reltup); -+ -+ checked = true; -+ } ++ 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); + -+ if (is_inh) -+ { -+ List *child_list = find_inheritance_children(relid); -+ ListCell *l; -+ -+ foreach(l, child_list) -+ selist = addEvalTriggerAccess(selist, lfirst_oid(l), -+ is_inh, cmdType); -+ } -+ + return selist; +} + +/* + * sepgsqlExprWalker + * -+ * This function walks on the given node tree recursively, to pick up -+ * all appeared tables, columns and functions. Their identifiers are -+ * chained swc->selist, and evaluated later. ++ * 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 and walkOpExprHelper are used to simplify its -+ * implementation. If swx->is_internal_use is true, it add a "use" -+ * permission to be evaluate, or a "select" permission otherwise. ++ * 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 -+walkVarHelper(sepgsqlWalkerContext *swc, Var *var) ++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 +{ -+ RangeTblEntry *rte; -+ queryStack *qstack; -+ Query *query; -+ int lv; ++ 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)); + -+ /* -+ * resolve external Var reference -+ */ -+ qstack = swc->qstack; -+ lv = var->varlevelsup; -+ while (lv > 0) ++ for (lv = var->varlevelsup; lv > 0; lv--) + { -+ Assert(!!qstack->parent); -+ qstack = qstack->parent; -+ lv--; ++ Assert(cur->parent != NULL); ++ cur = cur->parent; + } -+ query = qstack->query; -+ if (!query) -+ elog(ERROR, "SELinux: could not walk T_Var node in this context"); ++ query = cur->query; + + rte = rt_fetch(var->varno, query->rtable); + Assert(IsA(rte, RangeTblEntry)); + + if (rte->rtekind == RTE_RELATION) + { -+ /* -+ * table:{select/use} and column:{select/use} -+ */ -+ swc->selist = addEvalAttributeRTE(swc->selist, rte, var->varattno, -+ swc->is_internal_use -+ ? DB_COLUMN__USE : DB_COLUMN__SELECT); ++ 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) + { -+ Node *node = list_nth(rte->joinaliasvars, -+ var->varattno - 1); -+ -+ sepgsqlExprWalker(node, swc); -+ } -+} -+ -+static void -+walkOpExprHelper(sepgsqlWalkerContext *swc, Oid opid) -+{ -+ HeapTuple tuple; -+ Form_pg_operator oprform; -+ -+ tuple = SearchSysCache(OPEROID, ObjectIdGetDatum(opid), 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for operator %u", opid); -+ oprform = (Form_pg_operator) GETSTRUCT(tuple); -+ -+ swc->selist = addEvalPgProc(swc->selist, oprform->oprcode, -+ DB_PROCEDURE__EXECUTE); -+ /* -+ * NOTE: opr->oprrest and opr->oprjoin are internal use only -+ * and have no effect onto the data references, so we don't -+ * apply any checkings for them. -+ */ -+ ReleaseSysCache(tuple); -+} -+ -+static bool -+sepgsqlExprWalker(Node *node, sepgsqlWalkerContext *swc) -+{ -+ if (node == NULL) -+ return false; -+ -+ switch (nodeTag(node)) -+ { -+ case T_Var: -+ walkVarHelper(swc, (Var *) node); -+ break; -+ -+ case T_FuncExpr: -+ swc->selist = addEvalPgProc(swc->selist, -+ ((FuncExpr *) node)->funcid, -+ DB_PROCEDURE__EXECUTE); -+ break; -+ -+ case T_Aggref: -+ swc->selist = addEvalPgProc(swc->selist, -+ ((Aggref *) node)->aggfnoid, -+ DB_PROCEDURE__EXECUTE); -+ break; -+ -+ case T_OpExpr: -+ case T_DistinctExpr: /* typedef of OpExpr */ -+ case T_NullIfExpr: /* typedef of OpExpr */ -+ walkOpExprHelper(swc, ((OpExpr *) node)->opno); -+ break; -+ -+ case T_ScalarArrayOpExpr: -+ walkOpExprHelper(swc, ((ScalarArrayOpExpr *) node)->opno); -+ break; -+ -+ case T_Query: -+ /* -+ * Subquery within SubLink or CommonTableExpr -+ */ -+ proxyRteSubQuery(swc, (Query *) node); -+ break; -+ -+ case T_ArrayCoerceExpr: -+ { -+ ArrayCoerceExpr *ace = (ArrayCoerceExpr *) node; -+ -+ if (ace->elemfuncid != InvalidOid) -+ swc->selist = addEvalPgProc(swc->selist, -+ ace->elemfuncid, -+ DB_PROCEDURE__EXECUTE); -+ break; -+ } -+ case T_RowCompareExpr: -+ { -+ RowCompareExpr *rce = (RowCompareExpr *) node; -+ ListCell *l; -+ -+ foreach(l, rce->opnos) walkOpExprHelper(swc, lfirst_oid(l)); -+ break; -+ } -+ case T_SortClause: -+ case T_GroupClause: -+ { -+ SortClause *sc = (SortClause *) node; -+ Query *q = swc->qstack->query; -+ TargetEntry *tle -+ = get_sortgroupref_tle(sc->tleSortGroupRef, q->targetList); -+ -+ Assert(IsA(tle, TargetEntry)); -+ -+ walkOpExprHelper(swc, sc->sortop); -+ sepgsqlExprWalker((Node *)tle->expr, swc); -+ } -+ return false; /* expression_tree_walker does not suppor them */ -+ -+ default: -+ break; -+ } -+ -+ return expression_tree_walker(node, sepgsqlExprWalker, (void *) swc); -+} -+ -+static bool -+sepgsqlExprWalkerFlags(Node *node, sepgsqlWalkerContext *swc, bool is_internal_use) -+{ -+ bool saved_is_internal_use = swc->is_internal_use; -+ bool rc; -+ -+ swc->is_internal_use = is_internal_use; -+ rc = sepgsqlExprWalker(node, swc); -+ swc->is_internal_use = saved_is_internal_use; -+ -+ return rc; -+} -+ -+/* -+ * proxyJoinTree -+ * -+ * It appends SEvalItem of WHERE/JOIN ON clause, nodes in VALUE -+ * clause or function which returns a relation, or invokes -+ * proxyRteSubQuery recursively. -+ */ -+static void -+proxyJoinTree(sepgsqlWalkerContext *swc, Node *node) -+{ -+ Query *query = swc->qstack->query; -+ -+ if (node == NULL) -+ return; -+ -+ if (IsA(node, RangeTblRef)) -+ { -+ RangeTblRef *rtr = (RangeTblRef *) node; -+ RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable); -+ -+ Assert(IsA(rte, RangeTblEntry)); -+ -+ switch (rte->rtekind) ++ if (var->varattno == 0) + { -+ case RTE_RELATION: -+ if (rtr->rtindex != query->resultRelation) -+ { -+ swc->selist = addEvalRelationRTE(swc->selist, rte, -+ DB_TABLE__SELECT); -+ } -+ break; ++ wholeRefJoinWalkerContext jwcData; + -+ case RTE_SUBQUERY: -+ proxyRteSubQuery(swc, rte->subquery); -+ break; ++ jwcData.query = query; ++ jwcData.rtindex = var->varno; ++ jwcData.selist = swc->selist; ++ jwcData.perms = swc->is_internal_use ++ ? DB_COLUMN__USE : DB_COLUMN__SELECT; + -+ case RTE_FUNCTION: -+ sepgsqlExprWalkerFlags(rte->funcexpr, swc, false); -+ break; -+ -+ case RTE_VALUES: -+ sepgsqlExprWalkerFlags((Node *) rte->values_lists, swc, false); -+ break; -+ -+ default: -+ break; ++ wholeRefJoinWalker((Node *)query->jointree, &jwcData); ++ swc->selist = jwcData.selist; ++ } ++ else ++ { ++ Node *node = list_nth(rte->joinaliasvars, ++ var->varattno - 1); ++ sepgsqlExprWalker(node, swc); + } + } -+ else if (IsA(node, FromExpr)) ++} ++ ++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) + { -+ FromExpr *from = (FromExpr *) node; + ListCell *l; + -+ sepgsqlExprWalkerFlags(from->quals, swc, true); -+ foreach(l, from->fromlist) -+ proxyJoinTree(swc, lfirst(l)); -+ } -+ else if (IsA(node, JoinExpr)) -+ { -+ JoinExpr *join = (JoinExpr *) node; -+ -+ sepgsqlExprWalkerFlags(join->quals, swc, true); -+ proxyJoinTree(swc, join->larg); -+ proxyJoinTree(swc, join->rarg); -+ } -+ else -+ { -+ elog(ERROR, "SELinux: unexpected node type (%d)", nodeTag(node)); -+ } -+} -+ -+/* -+ * proxySetOperations -+ * -+ * It walks on a query tree recursively when set operations -+ * (UNION, INTERSECT, EXCEPT) are used. -+ * -+ */ -+static void -+proxySetOperations(sepgsqlWalkerContext *swc, Node *node) -+{ -+ Query *query = swc->qstack->query; -+ -+ if (node == NULL) -+ return; -+ -+ if (IsA(node, RangeTblRef)) -+ { -+ RangeTblRef *rtr = (RangeTblRef *) node; -+ RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable); -+ -+ Assert(IsA(rte, RangeTblEntry) -+ && rte->rtekind == RTE_SUBQUERY); -+ proxyRteSubQuery(swc, rte->subquery); -+ } -+ else if (IsA(node, SetOperationStmt)) -+ { -+ SetOperationStmt *sop = (SetOperationStmt *) node; -+ -+ proxySetOperations(swc, sop->larg); -+ proxySetOperations(swc, sop->rarg); -+ } -+ else -+ { -+ elog(ERROR, "SELinux: unexpected node (%d)", nodeTag(node)); -+ } -+} -+ -+/* -+ * proxyRteSubQuery -+ * -+ * It walks on the given DML Query to enumerate all appeared tables, -+ * columns and functions which include implementations of operator. -+ * While its walking, it generates a list of SEvalItemXXXX object -+ * to be evaluated later, and marks required permission on -+ * RangeTblEntry->pgaceTuplePerms. The swc->selist is copied to -+ * PlannedStmt->pgaceItem and evaluated on the hook invoked from -+ * the executor. RangeTblEntry->pgaceTuplePerms is copied to -+ * Scan->pgaceTuplePerms and it can be refered at sepgsqlExecScan() -+ * hook to apply tuple-level access controls. -+ */ -+static void -+proxyRteSubQuery(sepgsqlWalkerContext *swc, Query *query) -+{ -+ CmdType cmdType = query->commandType; -+ RangeTblEntry *rte = NULL; -+ struct queryStack qsData; -+ ListCell *l; -+ -+ /* -+ * push a query to queryStack -+ */ -+ qsData.parent = swc->qstack; -+ qsData.query = query; -+ swc->qstack = &qsData; -+ -+ if (cmdType != CMD_DELETE) -+ { -+ foreach(l, query->targetList) ++ foreach (l, query->targetList) + { + TargetEntry *tle = lfirst(l); + bool is_security = false; @@ -8526,79 +10620,158 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + + if (tle->resjunk && + tle->resname && -+ strcmp(tle->resname, SECURITY_SYSATTR_NAME) == 0) ++ strcmp(tle->resname, SecurityLabelAttributeName) == 0) + is_security = true; + -+ /* -+ * contents of junk target is not exposed to users, -+ * so it should be evaluated as "use" permission. -+ */ + if (tle->resjunk && !is_security) + { -+ sepgsqlExprWalkerFlags((Node *) tle->expr, swc, true); ++ sepgsqlExprWalkerFlags((Node *) tle->expr, &swcData, true); + continue; + } + -+ sepgsqlExprWalkerFlags((Node *) tle->expr, swc, false); ++ sepgsqlExprWalkerFlags((Node *) tle->expr, &swcData, false); + -+ if (cmdType != CMD_SELECT) ++ if (query->commandType != CMD_SELECT) + { -+ AttrNumber attno -+ = (is_security ? SecurityAttributeNumber : tle->resno); -+ uint32 perms -+ = (cmdType == CMD_UPDATE ? DB_COLUMN__UPDATE : DB_COLUMN__INSERT); ++ 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)); + -+ swc->selist = addEvalAttributeRTE(swc->selist, rte, attno, perms); ++ swcData.selist ++ = addEvalAttributeRTE(swcData.selist, rte, attno, perms); + } + } + } + else + { -+ /* -+ * NOTE: column level checks are not necessary for normal DELETE -+ */ ++ /* no need to check column-level permission for DELETE */ + rte = rt_fetch(query->resultRelation, query->rtable); + Assert(IsA(rte, RangeTblEntry)); + -+ swc->selist = addEvalRelationRTE(swc->selist, rte, DB_TABLE__DELETE); ++ swcData.selist ++ = addEvalRelationRTE(swcData.selist, rte, DB_TABLE__DELETE); + } + -+ proxyJoinTree(swc, (Node *) query->jointree); ++ 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->returningList, swc, false); -+ sepgsqlExprWalkerFlags((Node *) query->havingQual, swc, true); -+ sepgsqlExprWalkerFlags((Node *) query->sortClause, swc, true); -+ sepgsqlExprWalkerFlags((Node *) query->groupClause, swc, true); ++ return swcData.selist; ++} + -+ /* -+ * permission mark on the UNION/INTERSECT/EXCEPT -+ */ -+ proxySetOperations(swc, query->setOperations); ++static void ++walkRangeTblRefHelper(RangeTblRef *rtr, sepgsqlWalkerContext *swc) ++{ ++ Query *query = swc->query; ++ RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable); + -+ /* -+ * pop a query to queryStack -+ */ -+ swc->qstack = qsData.parent; ++ 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 ++walkSortClauseHelper(SortClause *sc, sepgsqlWalkerContext *swc) ++{ ++ Query *query = swc->query; ++ TargetEntry *tle ++ = get_sortgroupref_tle(sc->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, SortClause) || ++ IsA(node, GroupClause)) ++ { ++ walkSortClauseHelper((SortClause *) 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; +} + +/* -+ * sepgsqlProxyQuery ++ * sepgsqlPostQueryRewrite + * -+ * This function is invoked just after the given queries rewritten -+ * by the query rewriter. It invokes proxyRteSubQuery() for any -+ * DML queries to pick up all appeared database object and stores -+ * the list of them into Query->pgaceItem to evaluate later. ++ * 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 does not do anything for DDL queries because it is processed -+ * on sepgsqlProcessUtility() hook. ++ * It do nothing for DDL queries, because these are processed in ++ * sepgsqlProcessUtility() hook. + */ +List * -+sepgsqlProxyQuery(List *queryList) ++sepgsqlPostQueryRewrite(List *queryList) +{ -+ List *newList = NIL; + ListCell *l; + + foreach (l, queryList) @@ -8607,406 +10780,203 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + + Assert(IsA(query, Query)); + -+ switch (query->commandType) ++ if (query->commandType == CMD_SELECT || ++ query->commandType == CMD_UPDATE || ++ query->commandType == CMD_INSERT || ++ query->commandType == CMD_DELETE) + { -+ case CMD_SELECT: -+ case CMD_UPDATE: -+ case CMD_INSERT: -+ case CMD_DELETE: -+ { -+ sepgsqlWalkerContext swcData; -+ -+ memset(&swcData, 0, sizeof(swcData)); -+ -+ proxyRteSubQuery(&swcData, query); -+ query->pgaceItem = (Node *) swcData.selist; -+ -+ newList = lappend(newList, query); -+ } -+ break; -+ default: -+ newList = lappend(newList, query); -+ break; ++ query->pgaceItem ++ = (Node *) walkQueryHelper(query, NULL); + } + } + -+ return newList; ++ return queryList; +} + +/* -+ * sepgsqlEvaluateParams -+ * -+ * It checks permissions to execute functions just before -+ * parameter list is generated. -+ */ -+void -+sepgsqlEvaluateParams(List *params) -+{ -+ sepgsqlWalkerContext swcData; -+ -+ queryStack qsData; -+ -+ memset(&qsData, 0, sizeof(queryStack)); -+ memset(&swcData, 0, sizeof(sepgsqlWalkerContext)); -+ swcData.qstack = &qsData; -+ -+ sepgsqlExprWalkerFlags((Node *) params, &swcData, false); -+ -+ execVerifyQuery(swcData.selist); -+} -+ -+/* -+ * verityXXXX() -+ * -+ * These functions are invoked from execVerifyQuery, to evaluate -+ * SEvalItemXXXX objects generated at sepgsqlProxyQuery(). -+ */ -+ -+/* -+ * verifyPgClassPerms -+ * -+ * It evaluates SEvalItemRelation object to access tables. ++ * checkSelinuxEvalItem ++ * checks give SelinuxEvalItem object based on the security ++ * policy of SELinux. + */ +static void -+verifyPgClassPerms(Oid relid, bool inh, uint32 perms) ++checkSelinuxEvalItem(SelinuxEvalItem *seitem) +{ -+ HeapTuple tuple; ++ Form_pg_class relForm; ++ Form_pg_attribute attForm; ++ HeapTuple tuple; ++ AttrNumber attno; ++ const char *audit_name; ++ int index; ++ ++ Assert(IsA(seitem, SelinuxEvalItem)); + + /* -+ * prevent to modify pg_security directly ++ * Prevent to write pg_security by hand + */ -+ if (relid == SecurityRelationId -+ && (perms & (DB_TABLE__UPDATE | DB_TABLE__INSERT | DB_TABLE__DELETE))) ++ if (seitem->relid == SecurityRelationId && ++ (seitem->relperms & (DB_TABLE__UPDATE | DB_TABLE__INSERT | DB_TABLE__DELETE))) + ereport(ERROR, + (errcode(ERRCODE_SELINUX_ERROR), -+ errmsg("SELinux: user cannot modify pg_security directly"))); ++ errmsg("SELinux: could not modify pg_security by hand"))); + + /* -+ * check table:{required permissions} ++ * Permission checks on table + */ -+ tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); ++ tuple = SearchSysCache(RELOID, ++ ObjectIdGetDatum(seitem->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) -+ { -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), -+ SECCLASS_DB_TABLE, -+ (access_vector_t) perms, -+ sepgsqlTupleName(RelationRelationId, tuple)); -+ } -+ ReleaseSysCache(tuple); -+} -+ -+/* -+ * verifyPgAttributePerms -+ * -+ * It evaluates SEvalItemAttribute to access columns. -+ */ -+static void -+verifyPgAttributePerms(Oid relid, bool inh, AttrNumber attno, uint32 perms) -+{ -+ Form_pg_class clsForm; -+ HeapTuple tuple; -+ -+ tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for relation: %u", relid); -+ -+ clsForm = (Form_pg_class) GETSTRUCT(tuple); -+ if (clsForm->relkind != RELKIND_RELATION) ++ 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); + + /* -+ * 2. verify column perms ++ * Expand whole-row-reference + */ -+ if (attno == 0) ++ 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); + /* -+ * RECORD type permission check ++ * 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. + */ -+ Relation rel; -+ ScanKeyData skey; -+ SysScanDesc scan; -+ -+ ScanKeyInit(&skey, -+ Anum_pg_attribute_attrelid, -+ BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); -+ -+ rel = heap_open(AttributeRelationId, AccessShareLock); -+ scan = systable_beginscan(rel, AttributeRelidNumIndexId, -+ true, SnapshotNow, 1, &skey); -+ while ((tuple = systable_getnext(scan)) != NULL) ++ if (attForm->attisdropped) + { -+ Form_pg_attribute attForm = (Form_pg_attribute) GETSTRUCT(tuple); -+ -+ if (attForm->attisdropped || attForm->attnum < 1) -+ continue; -+ -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), -+ SECCLASS_DB_COLUMN, -+ perms, -+ sepgsqlTupleName(AttributeRelationId, tuple)); -+ } -+ systable_endscan(scan); -+ heap_close(rel, AccessShareLock); -+ -+ return; -+ } -+ /* -+ * check required column's permission -+ */ -+ tuple = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(relid), -+ Int16GetDatum(attno), 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for attribute %d of relation %u", -+ attno, relid); -+ -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), -+ SECCLASS_DB_COLUMN, -+ perms, -+ sepgsqlTupleName(AttributeRelationId, tuple)); -+ ReleaseSysCache(tuple); -+} -+ -+/* -+ * verifyPgProcedurePerms -+ * -+ * It evaluates SEvalItemProcedure object to access tables. -+ */ -+static void -+verifyPgProcPerms(Oid funcid, uint32 perms) -+{ -+ HeapTuple tuple; -+ security_context_t ncon; -+ -+ tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for procedure %d", funcid); -+ /* -+ * check domain transition -+ */ -+ ncon = sepgsqlClientCreateContext(HeapTupleGetSecurity(tuple), -+ SECCLASS_PROCESS); -+ if (strcmp(sepgsqlGetClientContext(), ncon)) -+ { -+ perms |= DB_PROCEDURE__ENTRYPOINT; -+ -+ sepgsqlComputePermission(sepgsqlGetClientContext(), -+ ncon, -+ SECCLASS_PROCESS, -+ PROCESS__TRANSITION, -+ NULL); -+ } -+ pfree(ncon); -+ -+ /* -+ * check procedure executiong permission -+ */ -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), -+ SECCLASS_DB_PROCEDURE, -+ perms, -+ sepgsqlTupleName(ProcedureRelationId, tuple)); -+ ReleaseSysCache(tuple); -+} -+ -+/* -+ * expandSEvalItemInheritance -+ * -+ * When a request to table/column is inheritable, we have to expand -+ * the target to child relations, because accessing a column within -+ * parent table also means accessing a column within child relation -+ * in same time. -+ * -+ * For example, when t2 and t3 inherits t1, we have to check permission -+ * on t2.x and t3.x for the request to t1.x. -+ * It is impossible to be done before, because we have a chance to -+ * change inheritance relationships between PREPARE and EXECUTE. -+ * So, we have to check it in execution phase. -+ */ -+static List * -+expandRelationInheritance(List *selist, Oid relid, uint32 perms) -+{ -+ List *inherits = find_all_inheritors(relid); -+ ListCell *l; -+ -+ foreach(l, inherits) -+ selist = addEvalRelation(selist, lfirst_oid(l), false, perms); -+ -+ return selist; -+} -+ -+static List * -+expandAttributeInheritance(List *selist, Oid relid, char *attname, -+ uint32 perms) -+{ -+ List *inherits = find_all_inheritors(relid); -+ ListCell *l; -+ -+ foreach(l, inherits) -+ { -+ Form_pg_attribute attr; -+ -+ HeapTuple tuple; -+ -+ if (!attname) -+ { -+ selist = addEvalAttribute(selist, lfirst_oid(l), false, 0, perms); ++ ReleaseSysCache(tuple); + continue; + } + -+ tuple = SearchSysCacheAttName(lfirst_oid(l), attname); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, -+ "SELinux: cache lookup failed for attribute %s of relation %u", -+ attname, lfirst_oid(l)); -+ -+ attr = (Form_pg_attribute) GETSTRUCT(tuple); -+ selist = addEvalAttribute(selist, lfirst_oid(l), false, -+ attr->attnum, perms); -+ ++ audit_name = sepgsqlTupleName(AttributeRelationId, tuple); ++ sepgsqlClientHasPermission(HeapTupleGetSecLabel(tuple), ++ SECCLASS_DB_COLUMN, ++ seitem->attperms[index], ++ audit_name); + ReleaseSysCache(tuple); + } -+ -+ return selist; +} + +static List * -+expandSEvalItemInheritance(List *selist) ++expandEvalItemInheritance(List *selist) +{ -+ SEvalItemRelation *ser; -+ SEvalItemAttribute *sea; + List *result = NIL; -+ ListCell *l; ++ List *inherits; ++ ListCell *l, *i; ++ int index; + -+ foreach(l, selist) ++ foreach (l, selist) + { -+ Node *node = lfirst(l); ++ SelinuxEvalItem *seitem = lfirst(l); + -+ result = lappend(result, node); -+ switch (nodeTag(node)) ++ Assert(IsA(seitem, SelinuxEvalItem)); ++ ++ if (!seitem->inh) + { -+ case T_SEvalItemRelation: -+ ser = (SEvalItemRelation *) node; -+ if (ser->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) + { -+ ser->inh = false; -+ result = expandRelationInheritance(result, -+ ser->relid, ser->perms); ++ /* ++ * 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; + } -+ break; -+ -+ case T_SEvalItemAttribute: -+ sea = (SEvalItemAttribute *) node; -+ if (sea->inh) ++ else + { -+ Form_pg_attribute attr; -+ HeapTuple tuple; ++ char *attname = get_attname(seitem->relid, attno); + -+ sea->inh = false; -+ if (sea->attno == 0) -+ { -+ result = expandAttributeInheritance(result, -+ sea->relid, -+ NULL, sea->perms); -+ break; -+ } ++ if (!attname) ++ elog(ERROR, "cache lookup failed for attribute %d of relation %u", ++ attno, seitem->relid); + -+ tuple = SearchSysCache(ATTNUM, -+ ObjectIdGetDatum(sea->relid), -+ Int16GetDatum(sea->attno), 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, -+ "SELinux: cache lookup failed for attribute %d of relation %u", -+ sea->attno, sea->relid); -+ attr = (Form_pg_attribute) GETSTRUCT(tuple); ++ attno = get_attnum(relid_inh, attname); ++ if (attno == InvalidAttrNumber) ++ elog(ERROR, "cache lookup failed for attribute %s of relation %u", ++ attname, relid_inh); + -+ result = expandAttributeInheritance(result, -+ sea->relid, -+ NameStr(attr->attname), -+ sea->perms); -+ ReleaseSysCache(tuple); ++ result = addEvalAttribute(result, relid_inh, false, ++ attno, seitem->attperms[index]); ++ pfree(attname); + } -+ break; -+ -+ case T_SEvalItemProcedure: -+ /* -+ * do nothing -+ */ -+ break; -+ -+ default: -+ elog(ERROR, "SELinux: Invalid node type (%d) in SEvalItemList", -+ nodeTag(node)); -+ break; ++ } + } + } + return result; +} + +/* -+ * execVerifyQuery -+ * -+ * This function scans the given list, and invokes proper function -+ * to evaluate it. -+ */ -+static void -+execVerifyQuery(List *selist) -+{ -+ SEvalItemRelation *ser; -+ SEvalItemAttribute *sea; -+ SEvalItemProcedure *sep; -+ ListCell *l; -+ -+ foreach(l, selist) -+ { -+ Node *node = lfirst(l); -+ -+ switch (nodeTag(node)) -+ { -+ case T_SEvalItemRelation: -+ ser = (SEvalItemRelation *) node; -+ verifyPgClassPerms(ser->relid, ser->inh, ser->perms); -+ break; -+ -+ case T_SEvalItemAttribute: -+ sea = (SEvalItemAttribute *) node; -+ verifyPgAttributePerms(sea->relid, sea->inh, sea->attno, -+ sea->perms); -+ break; -+ -+ case T_SEvalItemProcedure: -+ sep = (SEvalItemProcedure *) node; -+ verifyPgProcPerms(sep->funcid, sep->perms); -+ break; -+ -+ default: -+ elog(ERROR, "SELinux: Invalid node type (%d) in SEvalItemList", -+ nodeTag(node)); -+ break; -+ } -+ } -+} -+ -+/* -+ * sepgsqlVerifyQuery ++ * 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 SEvalItemXXXX objects generated in ++ * Query->pgaceItem is a list of SelinuxEvalItem objects generated in + * previous phase, and it is copied to PlannedStmt->pgaceItem in the + * optimizer. -+ * sepgsqlVerifyQuery expand relations/columns and append permissions -+ * to execute trigger functions, if necessary. ++ * 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 -+sepgsqlVerifyQuery(PlannedStmt *pstmt, int eflags) ++sepgsqlExecutorStart(QueryDesc *queryDesc, int eflags) +{ ++ PlannedStmt *pstmt = queryDesc->plannedstmt; + RangeTblEntry *rte; + List *selist; + ListCell *l; @@ -9014,8 +10984,9 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + /* + * EXPLAIN statement does not access any object. + */ -+ if ((eflags & EXEC_FLAG_EXPLAIN_ONLY) != 0) ++ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) + return; ++ + if (!pstmt->pgaceItem) + return; + @@ -9025,7 +10996,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + /* + * expand table inheritances + */ -+ selist = expandSEvalItemInheritance(selist); ++ selist = expandEvalItemInheritance(selist); + + /* + * add checks for access via trigger function @@ -9037,10 +11008,15 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + rte = rt_fetch(rindex, pstmt->rtable); + Assert(IsA(rte, RangeTblEntry)); + -+ selist = addEvalTriggerAccess(selist, rte->relid, rte->inh, -+ pstmt->commandType); ++ selist = addEvalTriggerFunction(selist, rte->relid, ++ pstmt->commandType); + } -+ execVerifyQuery(selist); ++ ++ /* ++ * Check SelinuxEvalItem ++ */ ++ foreach (l, selist) ++ checkSelinuxEvalItem((SelinuxEvalItem *) lfirst(l)); +} + +/* @@ -9050,69 +11026,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + */ + +/* -+ * checkTruncateStmt -+ * -+ * This function checks permissions of tuples within the given -+ * tables before TRUNCATE them. Because its meanings are same -+ * as unconditional DELETE logically, SE-PostgreSQL attempt to -+ * apply same permission for them operation. -+ * If there is a violated tuple at most, it stops to execute -+ * TRUNCATE and abort current trunsaction. -+ */ -+static void -+checkTruncateStmt(TruncateStmt *stmt) -+{ -+ Relation rel; -+ HeapScanDesc scan; -+ HeapTuple tuple; -+ List *relidList = NIL; -+ ListCell *l; -+ -+ foreach(l, stmt->relations) -+ { -+ RangeVar *rv = lfirst(l); -+ -+ relidList = lappend_oid(relidList, RangeVarGetRelid(rv, false)); -+ } -+ -+ if (stmt->behavior == DROP_CASCADE) -+ { -+ relidList = list_concat(relidList, heap_truncate_find_FKs(relidList)); -+ } -+ -+ foreach(l, relidList) -+ { -+ Oid relid = lfirst_oid(l); -+ -+ /* -+ * 1. db_table:{delete} -+ */ -+ tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); -+ if (!HeapTupleIsValid(tuple)) -+ elog(ERROR, "SELinux: cache lookup failed for relation %u", relid); -+ sepgsqlClientHasPermission(HeapTupleGetSecurity(tuple), -+ SECCLASS_DB_TABLE, -+ DB_TABLE__DELETE, -+ sepgsqlTupleName(RelationRelationId, tuple)); -+ ReleaseSysCache(tuple); -+ -+ /* -+ * 2. db_tuple:{delete} -+ */ -+ rel = heap_open(relid, AccessShareLock); -+ 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); -+ heap_close(rel, AccessShareLock); -+ } -+} -+ -+/* + * sepgsqlProcessUtility + * + * This function is invoked from the head of ProcessUtility(), and @@ -9125,13 +11038,12 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +{ + switch (nodeTag(parsetree)) + { -+ case T_TruncateStmt: -+ checkTruncateStmt((TruncateStmt *) parsetree); ++ case T_LoadStmt: ++ sepgsqlCheckModuleInstallPerms(((LoadStmt *)parsetree)->filename); + break; ++ + default: -+ /* -+ * do nothing -+ */ ++ /* do nothing */ + break; + } +} @@ -9179,10 +11091,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi + * check call trigger function + */ + if (isFrom) -+ selist = addEvalTriggerAccess(selist, RelationGetRelid(rel), -+ false, CMD_INSERT); ++ selist = addEvalTriggerFunction(selist, RelationGetRelid(rel), CMD_INSERT); + -+ execVerifyQuery(selist); ++ foreach (l, selist) ++ checkSelinuxEvalItem((SelinuxEvalItem *) lfirst(l)); +} + +/* @@ -9195,7 +11107,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +{ + security_context_t context; + security_class_t tclass -+ = sepgsqlProperFileObjectClass(fdesc, filename); ++ = sepgsqlFileObjectClass(fdesc, filename); + + if (fgetfilecon_raw(fdesc, &context) < 0) + ereport(ERROR, @@ -9289,45 +11201,35 @@ diff -rpNU3 base/src/backend/storage/ipc/ipci.c sepgsql/src/backend/storage/ipc/ addin_request_allowed = false; diff -rpNU3 base/src/backend/tcop/fastpath.c sepgsql/src/backend/tcop/fastpath.c --- base/src/backend/tcop/fastpath.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/tcop/fastpath.c 2008-06-14 02:36:58.000000000 +0900 -@@ -26,6 +26,7 @@ - #include "libpq/pqformat.h" - #include "mb/pg_wchar.h" ++++ sepgsql/src/backend/tcop/fastpath.c 2009-01-16 17:07:29.000000000 +0900 +@@ -28,6 +28,7 @@ #include "miscadmin.h" -+#include "security/pgace.h" #include "tcop/fastpath.h" #include "tcop/tcopprot.h" - #include "utils/acl.h" -@@ -353,6 +354,8 @@ HandleFunctionRequest(StringInfo msgBuf) - */ - InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, NULL, NULL); - -+ pgaceCallFunctionFastPath(fcinfo.flinfo); -+ - if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) - rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo); - else -diff -rpNU3 base/src/backend/tcop/postgres.c sepgsql/src/backend/tcop/postgres.c ---- base/src/backend/tcop/postgres.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql/src/backend/tcop/postgres.c 2008-06-14 02:36:58.000000000 +0900 -@@ -53,6 +53,7 @@ - #include "parser/parser.h" - #include "postmaster/autovacuum.h" - #include "rewrite/rewriteHandler.h" +#include "security/pgace.h" - #include "storage/freespace.h" - #include "storage/ipc.h" - #include "storage/proc.h" -@@ -629,6 +630,9 @@ pg_rewrite_query(Query *query) - { - /* don't rewrite utilities, just dump 'em into result list */ - querytree_list = list_make1(query); -+ -+ /* PGACE rewrite utility query, if necessary */ -+ querytree_list = pgaceProxyQuery(querytree_list); - } - else - { + #include "utils/acl.h" + #include "utils/lsyscache.h" + #include "utils/syscache.h" +@@ -347,6 +348,7 @@ HandleFunctionRequest(StringInfo msgBuf) + 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 -rpNU3 base/src/backend/tcop/pquery.c sepgsql/src/backend/tcop/pquery.c +--- base/src/backend/tcop/pquery.c 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/backend/tcop/pquery.c 2008-11-21 23:11:55.000000000 +0900 +@@ -560,7 +560,7 @@ PortalStart(Portal portal, ParamListInfo + Assert(pstmt->returningLists); + portal->tupDesc = + ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), +- false); ++ false, false); + } + + /* diff -rpNU3 base/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c --- base/src/backend/tcop/utility.c 2008-11-05 09:57:00.000000000 +0900 +++ sepgsql/src/backend/tcop/utility.c 2008-11-05 10:01:30.000000000 +0900 @@ -9350,7 +11252,7 @@ diff -rpNU3 base/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c /* diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c --- base/src/backend/utils/adt/ri_triggers.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/utils/adt/ri_triggers.c 2008-10-13 19:52:48.000000000 +0900 ++++ sepgsql/src/backend/utils/adt/ri_triggers.c 2008-12-28 01:06:59.000000000 +0900 @@ -37,6 +37,7 @@ #include "parser/parse_coerce.h" #include "parser/parse_relation.h" @@ -9363,7 +11265,7 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a int spi_result; Oid save_userid; bool save_secdefcxt; -+ Datum save_pgace; ++ Datum pgace_private = 0; Datum vals[RI_MAX_NUMKEYS * 2]; char nulls[RI_MAX_NUMKEYS * 2]; @@ -9376,7 +11278,7 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a - vals, nulls, - test_snapshot, crosscheck_snapshot, - false, false, limit); -+ save_pgace = pgaceBeginPerformCheckFK(query_rel, detectNewRows, save_userid); ++ pgaceBeginPerformCheckFK(query_rel, detectNewRows, save_userid, &pgace_private); + PG_TRY(); + { + /* Finally we can run the query. */ @@ -9387,17 +11289,17 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a + } + PG_CATCH(); + { -+ pgaceEndPerformCheckFK(query_rel, save_pgace); ++ pgaceEndPerformCheckFK(query_rel, pgace_private); + PG_RE_THROW(); + } + PG_END_TRY(); -+ pgaceEndPerformCheckFK(query_rel, save_pgace); ++ pgaceEndPerformCheckFK(query_rel, pgace_private); /* Restore UID */ SetUserIdAndContext(save_userid, save_secdefcxt); diff -rpNU3 base/src/backend/utils/cache/catcache.c sepgsql/src/backend/utils/cache/catcache.c --- base/src/backend/utils/cache/catcache.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/utils/cache/catcache.c 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/backend/utils/cache/catcache.c 2009-01-16 17:07:29.000000000 +0900 @@ -1313,6 +1313,38 @@ ReleaseCatCache(HeapTuple tuple) CatCacheRemoveCTup(ct->my_cache, ct); } @@ -9437,6 +11339,121 @@ diff -rpNU3 base/src/backend/utils/cache/catcache.c sepgsql/src/backend/utils/ca /* * SearchCatCacheList +diff -rpNU3 base/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/cache/plancache.c +--- base/src/backend/utils/cache/plancache.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/utils/cache/plancache.c 2009-02-02 11:58:34.000000000 +0900 +@@ -880,12 +880,14 @@ PlanCacheComputeResultDesc(List *stmt_li + if (IsA(node, Query)) + { + query = (Query *) node; +- return ExecCleanTypeFromTL(query->targetList, false); ++ return ExecCleanTypeFromTL(query->targetList, ++ false, false); + } + if (IsA(node, PlannedStmt)) + { + pstmt = (PlannedStmt *) node; +- return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); ++ return ExecCleanTypeFromTL(pstmt->planTree->targetlist, ++ false, false); + } + /* other cases shouldn't happen, but return NULL */ + break; +@@ -896,13 +898,15 @@ PlanCacheComputeResultDesc(List *stmt_li + { + query = (Query *) node; + Assert(query->returningList); +- return ExecCleanTypeFromTL(query->returningList, false); ++ return ExecCleanTypeFromTL(query->returningList, ++ false, false); + } + if (IsA(node, PlannedStmt)) + { + pstmt = (PlannedStmt *) node; + Assert(pstmt->returningLists); +- return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false); ++ return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), ++ false, false); + } + /* other cases shouldn't happen, but return NULL */ + break; +diff -rpNU3 base/src/backend/utils/cache/relcache.c sepgsql/src/backend/utils/cache/relcache.c +--- base/src/backend/utils/cache/relcache.c 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/backend/utils/cache/relcache.c 2009-02-02 11:58:34.000000000 +0900 +@@ -54,6 +54,7 @@ + #include "optimizer/prep.h" + #include "optimizer/var.h" + #include "rewrite/rewriteDefine.h" ++#include "security/pgace.h" + #include "storage/fd.h" + #include "storage/smgr.h" + #include "utils/builtins.h" +@@ -324,7 +325,13 @@ AllocateRelationDesc(Relation relation, + /* initialize relation tuple form */ + relation->rd_rel = relationForm; + +- /* and allocate attribute tuple form storage */ ++ /* ++ * and allocate attribute tuple form storage ++ * ++ * Please note that relation->rd_att->tdhasseclabel should 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 */ +@@ -877,6 +884,10 @@ RelationBuildDesc(Oid targetRelId, Relat + /* extract reloptions if any */ + RelationParseRelOptions(relation, pg_class_tuple); + ++ /* fixup relation->rd_att->tdhasseclabel */ ++ relation->rd_att->tdhasseclabel ++ = pgaceTupleDescHasSecLabel(relation, NIL); ++ + /* + * initialize the relation lock manager information + */ +@@ -1462,6 +1473,12 @@ formrdesc(const char *relationName, Oid + relation->rd_rel->relfilenode = RelationGetRelid(relation); + + /* ++ * Fixup relation->rd_att->tdhasseclabel ++ */ ++ RelationGetDescr(relation)->tdhasseclabel ++ = pgaceTupleDescHasSecLabel(relation, NIL); ++ ++ /* + * initialize the relation lock manager information + */ + RelationInitLockInfo(relation); /* see lmgr.c */ +@@ -2687,6 +2704,13 @@ BuildHardcodedDescriptor(int natts, Form + + 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->tdhasseclabel does not ++ * give 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; +@@ -3446,6 +3470,12 @@ load_relcache_init_file(void) + rel->rd_options = NULL; + } + ++ /* ++ * fixup rel->rd_att->tdhasseclabel ++ */ ++ rel->rd_att->tdhasseclabel ++ = pgaceTupleDescHasSecLabel(rel, NIL); ++ + /* mark not-null status */ + if (has_not_null) + { diff -rpNU3 base/src/backend/utils/cache/syscache.c sepgsql/src/backend/utils/cache/syscache.c --- base/src/backend/utils/cache/syscache.c 2008-01-07 23:51:33.000000000 +0900 +++ sepgsql/src/backend/utils/cache/syscache.c 2008-06-14 02:36:58.000000000 +0900 @@ -9574,7 +11591,7 @@ diff -rpNU3 base/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/ini CommitTransactionCommand(); diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc.c --- base/src/backend/utils/misc/guc.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/utils/misc/guc.c 2008-09-25 15:22:04.000000000 +0900 ++++ sepgsql/src/backend/utils/misc/guc.c 2008-12-28 01:06:59.000000000 +0900 @@ -54,6 +54,7 @@ #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" @@ -9583,49 +11600,42 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc #include "storage/fd.h" #include "storage/freespace.h" #include "tcop/tcopprot.h" -@@ -268,11 +269,12 @@ static int max_index_keys; - static int max_identifier_length; - static int block_size; - static bool integer_datetimes; -+static char *pgace_security_feature; - - /* should be static, but commands/variable.c needs to get at these */ +@@ -273,7 +274,6 @@ static bool integer_datetimes; char *role_string; char *session_authorization_string; -- -+char *sepostgresql_mode; +- /* * Displayable names for context types (enum GucContext) -@@ -2460,6 +2462,27 @@ static struct config_string ConfigureNam + * +@@ -2460,6 +2460,26 @@ static struct config_string ConfigureNam }, #endif /* USE_SSL */ + { -+ {"pgace_security_feature", PGC_INTERNAL, PRESET_OPTIONS, -+ gettext_noop("Shows the guest of PGACE security framework"), -+ NULL, -+ GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE ++ {"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_security_feature, -+ NULL, NULL, pgaceShowSecurityFeature, ++ &pgace_feature_string, ++ "none", pgaceAssignFeatureString, NULL, + }, +#ifdef HAVE_SELINUX + { + {"sepostgresql", PGC_POSTMASTER, PRESET_OPTIONS, -+ gettext_noop("SE-PostgreSQL working mode"), -+ gettext_noop("Valid values are DEFAULT, PERMISSIVE, ENFORCING, DISABLED"), -+ 0, ++ gettext_noop("SE-PostgreSQL mode (default|permissive|enforcing|disabled)"), ++ NULL, + }, -+ &sepostgresql_mode, -+ "default", NULL, NULL, ++ &sepostgresql_mode_string, ++ "default", sepgsqlAssignModeString, NULL, + }, +#endif + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL -@@ -3300,6 +3323,8 @@ ResetAllOptions(void) +@@ -3300,6 +3320,8 @@ ResetAllOptions(void) { int i; @@ -9634,7 +11644,7 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc for (i = 0; i < num_guc_variables; i++) { struct config_generic *gconf = guc_variables[i]; -@@ -4972,6 +4997,7 @@ ExecSetVariableStmt(VariableSetStmt *stm +@@ -4972,6 +4994,7 @@ ExecSetVariableStmt(VariableSetStmt *stm { case VAR_SET_VALUE: case VAR_SET_CURRENT: @@ -9642,7 +11652,7 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc set_config_option(stmt->name, ExtractSetVariableArgs(stmt), (superuser() ? PGC_SUSET : PGC_USERSET), -@@ -5029,6 +5055,7 @@ ExecSetVariableStmt(VariableSetStmt *stm +@@ -5029,6 +5052,7 @@ ExecSetVariableStmt(VariableSetStmt *stm break; case VAR_SET_DEFAULT: case VAR_RESET: @@ -9650,7 +11660,7 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc set_config_option(stmt->name, NULL, (superuser() ? PGC_SUSET : PGC_USERSET), -@@ -5357,6 +5384,9 @@ EmitWarningsOnPlaceholders(const char *c +@@ -5357,6 +5381,9 @@ EmitWarningsOnPlaceholders(const char *c void GetPGVariable(const char *name, DestReceiver *dest) { @@ -9660,70 +11670,126 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc if (guc_name_compare(name, "all") == 0) ShowAllGUCConfig(dest); else +diff -rpNU3 base/src/backend/utils/misc/postgresql.conf.sample sepgsql/src/backend/utils/misc/postgresql.conf.sample +--- base/src/backend/utils/misc/postgresql.conf.sample 2008-02-03 01:11:28.000000000 +0900 ++++ sepgsql/src/backend/utils/misc/postgresql.conf.sample 2008-12-28 01:19:14.000000000 +0900 +@@ -487,6 +487,12 @@ + + + #------------------------------------------------------------------------------ ++# ENHANCED SECURITY OPTIONS ++#------------------------------------------------------------------------------ ++ ++#pgace_feature = 'none' ++ ++#------------------------------------------------------------------------------ + # CUSTOMIZED OPTIONS + #------------------------------------------------------------------------------ + +diff -rpNU3 base/src/include/access/heapam.h sepgsql/src/include/access/heapam.h +--- base/src/include/access/heapam.h 2008-03-19 09:48:23.000000000 +0900 ++++ sepgsql/src/include/access/heapam.h 2008-11-21 23:11:55.000000000 +0900 +@@ -249,7 +249,7 @@ extern void heap_free_minimal_tuple(Mini + extern MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup); + extern HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup); + extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup); +-extern HeapTuple heap_addheader(int natts, bool withoid, ++extern HeapTuple heap_addheader(int natts, bool withoid, bool withsecurity, + Size structlen, void *structure); + + /* in heap/pruneheap.c */ diff -rpNU3 base/src/include/access/htup.h sepgsql/src/include/access/htup.h --- base/src/include/access/htup.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/access/htup.h 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/include/access/htup.h 2008-12-28 01:06:59.000000000 +0900 @@ -161,7 +161,7 @@ typedef HeapTupleHeaderData *HeapTupleHe #define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ #define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ #define HEAP_HASOID 0x0008 /* has an object-id field */ -/* bit 0x0010 is available */ -+#define HEAP_HASSECURITY 0x0010 /* has an security attribute field */ ++#define HEAP_HAS_SECLABEL 0x0010 /* has an security label field */ #define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */ #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ #define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */ -@@ -347,6 +347,34 @@ do { \ +@@ -288,6 +288,9 @@ do { \ + (tup)->t_choice.t_datum.datum_typmod = (typmod) \ + ) + ++#define HeapTupleHeaderHasOid(tup) \ ++ ((tup)->t_infomask & HEAP_HASOID) ++ + #define HeapTupleHeaderGetOid(tup) \ + ( \ + ((tup)->t_infomask & HEAP_HASOID) ? \ +@@ -347,6 +350,34 @@ do { \ (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \ ) -+#define HeapTupleHeaderHasSecurity(tup) \ -+ ((tup)->t_infomask & HEAP_HASSECURITY) ++#define HeapTupleHeaderHasSecLabel(tup) \ ++ ((tup)->t_infomask & HEAP_HAS_SECLABEL) + -+#define HeapTupleHeaderGetSecurity(tup) \ ++#define HeapTupleHeaderGetSecLabel(tup) \ + ( \ -+ HeapTupleHeaderHasSecurity(tup) \ ++ HeapTupleHeaderHasSecLabel(tup) \ + ? (*((Oid *)((char *)(tup) + (tup)->t_hoff \ -+ - (((tup)->t_infomask & HEAP_HASOID) ? sizeof(Oid) : 0) \ ++ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ + - sizeof(Oid)))) \ + : InvalidOid \ + ) + -+#define HeapTupleHeaderSetSecurity(tup, security) \ ++#define HeapTupleHeaderSetSecLabel(tup, seclabel) \ + do { \ -+ Assert(HeapTupleHeaderHasSecurity(tup)); \ ++ Assert(HeapTupleHeaderHasSecLabel(tup)); \ + *((Oid *)((char *)(tup) + (tup)->t_hoff \ -+ - (((tup)->t_infomask & HEAP_HASOID) ? sizeof(Oid) : 0) \ -+ - sizeof(Oid))) = (security); \ ++ - (HeapTupleHeaderHasOid(tup) ? sizeof(Oid) : 0) \ ++ - sizeof(Oid))) = (seclabel); \ + } while(0) + -+#define HeapTupleHasSecurity(tuple) \ -+ HeapTupleHeaderHasSecurity((tuple)->t_data) ++#define HeapTupleHasSecLabel(tuple) \ ++ HeapTupleHeaderHasSecLabel((tuple)->t_data) + -+#define HeapTupleGetSecurity(tuple) \ -+ HeapTupleHeaderGetSecurity((tuple)->t_data) ++#define HeapTupleGetSecLabel(tuple) \ ++ HeapTupleHeaderGetSecLabel((tuple)->t_data) + -+#define HeapTupleSetSecurity(tuple, security) \ -+ HeapTupleHeaderSetSecurity((tuple)->t_data, (security)) ++#define HeapTupleSetSecLabel(tuple, seclabel) \ ++ HeapTupleHeaderSetSecLabel((tuple)->t_data, (seclabel)) /* * BITMAPLEN(NATTS) - -@@ -402,8 +430,12 @@ do { \ +@@ -402,8 +433,8 @@ do { \ #define MaxTransactionIdAttributeNumber (-5) #define MaxCommandIdAttributeNumber (-6) #define TableOidAttributeNumber (-7) -+#ifdef SECURITY_SYSATTR_NAME -+#define SecurityAttributeNumber (-8) -+#define FirstLowInvalidHeapAttributeNumber (-9) -+#else - #define FirstLowInvalidHeapAttributeNumber (-8) +-#define FirstLowInvalidHeapAttributeNumber (-8) - -+#endif ++#define SecurityLabelAttributeNumber (-8) ++#define FirstLowInvalidHeapAttributeNumber (-9) /* * MinimalTuple is an alternative representation that is used for transient +@@ -548,6 +579,9 @@ typedef HeapTupleData *HeapTuple; + #define HeapTupleClearHeapOnly(tuple) \ + HeapTupleHeaderClearHeapOnly((tuple)->t_data) + ++#define HeapTupleHasOid(tuple) \ ++ HeapTupleHeaderHasOid((tuple)->t_data) ++ + #define HeapTupleGetOid(tuple) \ + HeapTupleHeaderGetOid((tuple)->t_data) + +diff -rpNU3 base/src/include/access/tupdesc.h sepgsql/src/include/access/tupdesc.h +--- base/src/include/access/tupdesc.h 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/include/access/tupdesc.h 2008-12-28 01:06:59.000000000 +0900 +@@ -75,6 +75,7 @@ typedef struct tupleDesc + Oid tdtypeid; /* composite type ID for tuple type */ + int32 tdtypmod; /* typmod for tuple type */ + bool tdhasoid; /* tuple has oid attribute in its header */ ++ bool tdhasseclabel; /* tuple has security label in its header */ + int tdrefcount; /* reference count, or -1 if not counting */ + } *TupleDesc; + diff -rpNU3 base/src/include/catalog/heap.h sepgsql/src/include/catalog/heap.h --- base/src/include/catalog/heap.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/catalog/heap.h 2008-06-18 17:25:44.000000000 +0900 ++++ sepgsql/src/include/catalog/heap.h 2008-12-05 16:28:22.000000000 +0900 @@ -52,7 +52,8 @@ extern Oid heap_create_with_catalog(cons int oidinhcount, OnCommitAction oncommit, @@ -9748,7 +11814,7 @@ diff -rpNU3 base/src/include/catalog/heap.h sepgsql/src/include/catalog/heap.h extern Form_pg_attribute SystemAttributeByName(const char *attname, bool relhasoids); -+extern bool SystemAttributeIsWritable(AttrNumber attno, bool relhasoids); ++extern bool SystemAttributeIsWritable(AttrNumber attnum); + extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind); @@ -9770,12 +11836,12 @@ diff -rpNU3 base/src/include/catalog/indexing.h sepgsql/src/include/catalog/inde diff -rpNU3 base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/pg_attribute.h --- base/src/include/catalog/pg_attribute.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/catalog/pg_attribute.h 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/include/catalog/pg_attribute.h 2008-12-28 01:06:59.000000000 +0900 @@ -282,6 +282,7 @@ DATA(insert ( 1247 cmin 29 0 4 -4 0 DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); -+DATA(insert ( 1247 SECURITY_SYSATTR_NAME 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); ++DATA(insert ( 1247 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); /* ---------------- * pg_proc @@ -9783,7 +11849,7 @@ diff -rpNU3 base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/ DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); -+DATA(insert ( 1255 SECURITY_SYSATTR_NAME 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); ++DATA(insert ( 1255 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); /* ---------------- * pg_attribute @@ -9791,7 +11857,7 @@ diff -rpNU3 base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/ DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); -+DATA(insert ( 1249 SECURITY_SYSATTR_NAME 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); ++DATA(insert ( 1249 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); /* ---------------- * pg_class @@ -9799,7 +11865,7 @@ diff -rpNU3 base/src/include/catalog/pg_attribute.h sepgsql/src/include/catalog/ DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); -+DATA(insert ( 1259 SECURITY_SYSATTR_NAME 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); ++DATA(insert ( 1259 security_context 25 0 -1 -8 0 -1 -1 f x i t f f t 0)); /* ---------------- * pg_index @@ -9874,22 +11940,53 @@ diff -rpNU3 base/src/include/catalog/pg_security.h sepgsql/src/include/catalog/p +#define Anum_pg_security_seclabel 1 + +#endif /* PG_SELINUX_H */ +diff -rpNU3 base/src/include/executor/executor.h sepgsql/src/include/executor/executor.h +--- base/src/include/executor/executor.h 2008-01-07 23:51:33.000000000 +0900 ++++ sepgsql/src/include/executor/executor.h 2008-12-28 01:06:59.000000000 +0900 +@@ -116,7 +116,7 @@ extern TupleHashEntry FindTupleHashEntry + /* + * prototypes from functions in execJunk.c + */ +-extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, ++extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid, bool hassecurity, + TupleTableSlot *slot); + extern JunkFilter *ExecInitJunkFilterConversion(List *targetList, + TupleDesc cleanTupType, +@@ -140,6 +140,7 @@ extern void ExecutorEnd(QueryDesc *query + extern void ExecutorRewind(QueryDesc *queryDesc); + extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); + extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); ++extern bool ExecContextForcesSecLabel(PlanState *planstate, bool *hasseclabel); + extern void ExecConstraints(ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, EState *estate); + extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, +@@ -199,8 +200,8 @@ extern void ExecInitScanTupleSlot(EState + 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 ExecTypeFromTL(List *targetList, bool hasoid, bool hasseclabel); ++extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid, bool hasseclabel); + extern TupleDesc ExecTypeFromExprList(List *exprList); + extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); + diff -rpNU3 base/src/include/executor/tuptable.h sepgsql/src/include/executor/tuptable.h --- base/src/include/executor/tuptable.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/executor/tuptable.h 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/include/executor/tuptable.h 2008-12-28 01:06:59.000000000 +0900 @@ -118,6 +118,9 @@ typedef struct TupleTableSlot 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_security; /* for security attribute */ ++ Datum tts_seclabel; /* for security label */ } TupleTableSlot; /* diff -rpNU3 base/src/include/fmgr.h sepgsql/src/include/fmgr.h --- base/src/include/fmgr.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/fmgr.h 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/include/fmgr.h 2009-01-16 17:07:29.000000000 +0900 @@ -52,6 +52,8 @@ typedef struct FmgrInfo void *fn_extra; /* extra space for use by handler */ MemoryContext fn_mcxt; /* memory context to store fn_extra in */ @@ -9922,15 +12019,14 @@ diff -rpNU3 base/src/include/libpq/be-fsstubs.h sepgsql/src/include/libpq/be-fss * Probably these should have had the underscore-free names, diff -rpNU3 base/src/include/nodes/nodes.h sepgsql/src/include/nodes/nodes.h --- base/src/include/nodes/nodes.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/nodes/nodes.h 2008-06-14 02:36:58.000000000 +0900 -@@ -358,7 +358,10 @@ typedef enum NodeTag ++++ sepgsql/src/include/nodes/nodes.h 2009-01-21 17:02:57.000000000 +0900 +@@ -358,7 +358,9 @@ typedef enum NodeTag */ T_TriggerData = 950, /* in commands/trigger.h */ T_ReturnSetInfo, /* in nodes/execnodes.h */ - T_TIDBitmap /* in nodes/tidbitmap.h */ + T_TIDBitmap, /* in nodes/tidbitmap.h */ -+ T_SEvalItemRelation, /* in nodes/security.h */ -+ T_SEvalItemAttribute, /* in nodes/security.h */ ++ T_SelinuxEvalItem, /* in nodes/security.h */ + T_SEvalItemProcedure, /* in nodes/security.h */ } NodeTag; @@ -10016,8 +12112,8 @@ diff -rpNU3 base/src/include/nodes/plannodes.h sepgsql/src/include/nodes/plannod /* ---------------- diff -rpNU3 base/src/include/nodes/relation.h sepgsql/src/include/nodes/relation.h ---- base/src/include/nodes/relation.h 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql/src/include/nodes/relation.h 2008-06-14 02:36:58.000000000 +0900 +--- base/src/include/nodes/relation.h 2009-02-02 11:47:17.000000000 +0900 ++++ sepgsql/src/include/nodes/relation.h 2009-02-02 11:58:34.000000000 +0900 @@ -366,6 +366,8 @@ typedef struct RelOptInfo * list just to avoid recomputing the best inner indexscan repeatedly for * similar outer relations. See comments for InnerIndexscanInfo. @@ -10029,8 +12125,8 @@ diff -rpNU3 base/src/include/nodes/relation.h sepgsql/src/include/nodes/relation /* diff -rpNU3 base/src/include/nodes/security.h sepgsql/src/include/nodes/security.h --- base/src/include/nodes/security.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/include/nodes/security.h 2008-06-15 22:24:53.000000000 +0900 -@@ -0,0 +1,58 @@ ++++ sepgsql/src/include/nodes/security.h 2009-01-21 17:02:57.000000000 +0900 +@@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * src/include/nodes/security.h @@ -10047,51 +12143,33 @@ diff -rpNU3 base/src/include/nodes/security.h sepgsql/src/include/nodes/security +#include "nodes/nodes.h" + +/* -+ * SEvalItemRelation ++ * SelinuxEvalItem + * -+ * SE-PostgreSQL permission evaluation item for a relation -+ */ -+typedef struct SEvalItemRelation { -+ NodeTag type; -+ -+ uint32 perms; -+ -+ Oid relid; -+ bool inh; -+} SEvalItemRelation; -+ -+/* -+ * SEvalItemAttribute ++ * 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. + * -+ * SE-PostgreSQL permission evaluation item for an attribute ++ * NOTE: attperms array can contains system attributes and ++ * whole-row-reference, so it is indexed as ++ * attperms[(attnum) + FirstLowInvalidHeapAttributeNumber - 1] + */ -+typedef struct SEvalItemAttribute { -+ NodeTag type; ++typedef struct SelinuxEvalItem ++{ ++ NodeTag type; + -+ uint32 perms; ++ Oid relid; /* relation id */ ++ bool inh; /* flags to inheritable/only */ + -+ Oid relid; -+ bool inh; -+ AttrNumber attno; -+} SEvalItemAttribute; -+ -+/* -+ * SEvalItemProcedure -+ * -+ * SE-PostgreSQL permission evaluation item for a procedure -+ */ -+typedef struct SEvalItemProcedure { -+ NodeTag type; -+ -+ uint32 perms; -+ -+ Oid funcid; -+} SEvalItemProcedure; ++ uint32 relperms; /* required permissions on table */ ++ uint32 nattrs; /* length of attperms */ ++ uint32 *attperms; /* required permissions on columns */ ++} SelinuxEvalItem; + +#endif /* NODES_SECURITY_H */ diff -rpNU3 base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in --- base/src/include/pg_config.h.in 2008-01-28 16:06:37.000000000 +0900 -+++ sepgsql/src/include/pg_config.h.in 2008-11-04 10:30:20.000000000 +0900 ++++ sepgsql/src/include/pg_config.h.in 2008-12-12 18:45:55.000000000 +0900 @@ -366,6 +366,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SECURITY_PAM_APPL_H @@ -10102,20 +12180,10 @@ diff -rpNU3 base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in /* Define to 1 if you have the `setproctitle' function. */ #undef HAVE_SETPROCTITLE -@@ -637,6 +640,9 @@ - your system. */ - #undef PTHREAD_CREATE_JOINABLE - -+/* The name of security attribute. */ -+#undef SECURITY_SYSATTR_NAME -+ - /* The size of a `size_t', as computed by sizeof. */ - #undef SIZEOF_SIZE_T - diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace.h --- base/src/include/security/pgace.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/include/security/pgace.h 2008-10-13 17:08:55.000000000 +0900 -@@ -0,0 +1,1231 @@ ++++ sepgsql/src/include/security/pgace.h 2009-01-21 17:26:07.000000000 +0900 +@@ -0,0 +1,194 @@ +/* + * include/security/pgace.h + * headers for PostgreSQL Access Control Extension (PGACE) @@ -10130,9 +12198,12 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +#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/builtins.h" ++#include "utils/guc.h" +#include "utils/rel.h" + +#ifdef HAVE_SELINUX @@ -10140,1186 +12211,142 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +#endif + +/* -+ * The definitions of PGACE hooks are follows: -+ * -+ * These are declared as static inline functions which give us no effect -+ * in the default (no security modules are enabled), and independent from -+ * its platform. -+ * -+ * The purpose of PGACE framework is to provide a security subsystems -+ * common hooks to apply its access controls, and minimize the impact -+ * to add a new security subsystem. -+ * -+ * (*) We calls the security subsystem implemented on PGACE framework -+ * as "the guest", in this comment. -+ * -+ * When a security module uses this framework, is has to add a #if .. #endif -+ * block into the needed hooks, as follows: -+ * -+ * ------------ -+ * static inline bool -+ * pgaceHeapTupleInsert(Relation rel, HeapTuple tuple, -+ * bool is_internal, bool with_returning) -+ * { -+ * #if defined(HAVE_SELINUX) -+ * if (sepgsqlIsEnabled()) -+ * return sepgsqlHeapTupleInsert(rel, tuple, -+ * is_internal, -+ * with_returning); -+ * #elif defined(HAVE_FOO_SECURITY) -+ * if (fooIsEnabled()) -+ * return fooHeapTupleInsert(rel, tuple, -+ * is_internal, -+ * with_returning); -+ * #endif -+ * return true; -+ * } -+ * ____________ -+ * -+ * It can invokes specific security subsystem and the callee makes -+ * its decision whether the required access it allowed, or not. -+ * When no security module is available, these hooks have to keep -+ * the default behaivior to keep compatibility. -+ * In this case, pgaceHeapTupleInsert() has to return 'true'. -+ * -+ * Any hook has a comment to show the purpose of itself. -+ * Please look at this one to understand each hooks. ++ * pgace_feature : GUC parameter to choose an enhanced security feature + */ ++typedef enum ++{ ++ PGACE_FEATURE_NONE, ++#ifdef HAVE_SELINUX ++ PGACE_FEATURE_SELINUX, ++#endif ++} PgaceFeatureOpts; + -+/****************************************************************** -+ * Shows the PGACE guest identifier -+ ******************************************************************/ ++extern int pgace_feature; ++extern char *pgace_feature_string; + +/* -+ * pgaceSecurityFeatureIdentity -+ * -+ * This hook has to return unique identifier of the PGACE guest. -+ * A GUC parameter of 'pgace_security_feature' shows this value. ++ * Attribute names for the system-defined attributes + */ ++#define SecurityLabelAttributeName "security_context" + -+static inline const char * -+pgaceSecurityFeatureIdentity(void) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return "selinux"; -+#endif -+ return "nothing"; -+} -+ -+/****************************************************************** ++/* + * Initialization hooks -+ ******************************************************************/ ++ */ ++extern Size pgaceShmemSize(void); ++extern void pgaceInitialize(bool is_bootstrap); ++extern pid_t pgaceStartupWorkerProcess(void); + +/* -+ * 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. -+ */ -+static inline Size -+pgaceShmemSize(void) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlShmemSize(); -+#endif -+ 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. -+ */ -+static inline void -+pgaceInitialize(bool is_bootstrap) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlInitialize(is_bootstrap); -+#endif -+} -+ -+/* -+ * 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. -+ */ -+static inline pid_t -+pgaceStartupWorkerProcess(void) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlStartupWorkerProcess(); -+#endif -+ return (pid_t) 0; -+} -+ -+/****************************************************************** + * 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); + +/* -+ * pgaceProxyQuery -+ * -+ * 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. ++ * Function related hooks + */ -+static inline List * -+pgaceProxyQuery(List *queryList) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlProxyQuery(queryList); -+#endif -+ return queryList; -+} ++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 *pgace_private); ++extern void pgaceEndPerformCheckFK(Relation rel, Datum pgace_private); ++extern bool pgaceAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple); + +/* -+ * pgaceIsAllowPlannerHook -+ * -+ * The guest can control whether planner_hook is available, or not. -+ * It returns false, if it is not allowed to apply planner_hook. -+ * -+ * The purpose of this hook is to make sure pgace opaque data are delivered -+ * to PlannedStmt::pgaceItem and Scan::pgaceTuplePerms, because they are -+ * copied in standard_planner(). Overriding planner_hook has a possibility -+ * to prevent the guest works correctly. ++ * Misc hooks + */ -+static inline bool -+pgaceIsAllowPlannerHook(void) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return false; -+#endif -+ return true; -+} ++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); + +/* -+ * pgaceExecutorStart -+ * -+ * This hook is invoked on the head of ExecutorStart(). -+ * -+ * The arguments of this hook are come from the ones of ExecutorStart -+ * as is. ++ * COPY TO/FROM statement hooks + */ -+static inline void -+pgaceExecutorStart(QueryDesc *queryDesc, int eflags) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlVerifyQuery(queryDesc->plannedstmt, eflags); -+#endif -+} ++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); + +/* -+ * 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. -+ */ -+static inline bool -+pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlExecScan(scan, rel, slot); -+#endif -+ return true; -+} -+ -+/* -+ * pgaceProcessUtility -+ * -+ * This hooks is invoked on the head of ProcessUtility(). -+ */ -+static inline void -+pgaceProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlProcessUtility(parsetree, params, isTopLevel); -+#endif -+} -+ -+/* -+ * pgaceEvaluateParams -+ * -+ * This hook is invoked just before parameter lists are evaluated -+ * at EvaluateParams(). -+ */ -+static inline void -+pgaceEvaluateParams(List *params) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlEvaluateParams(params); -+#endif -+} -+ -+ -+/****************************************************************** -+ * 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. -+ */ -+static inline bool -+pgaceHeapTupleInsert(Relation rel, HeapTuple tuple, -+ bool is_internal, bool with_returning) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlHeapTupleInsert(rel, tuple, -+ is_internal, -+ with_returning); -+#endif -+ 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. -+ */ -+static inline bool -+pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup, -+ bool is_internal, bool with_returning) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlHeapTupleUpdate(rel, otid, newtup, -+ is_internal, -+ with_returning); -+#endif -+ 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. -+ */ -+static inline bool -+pgaceHeapTupleDelete(Relation rel, ItemPointer otid, -+ bool is_internal, bool with_returning) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlHeapTupleDelete(rel, otid, -+ is_internal, -+ with_returning); -+#endif -+ return true; -+} -+ -+/****************************************************************** -+ * Extended SQL statement hooks -+ ******************************************************************/ -+ -+/* -+ * PGACE framework provides its guest facilities to manage security -+ * attribute of database object, using an extended SQL statement. -+ * -+ * For example: -+ * CREATE TABLE tbl ( -+ * x integer, -+ * y text -+ * ) CONTEXT = 'system_u:object_r:sepgsql_ro_table_t:Classified', -+ * -+ * In SE-PostgreSQL, this statement enables to create a new table -+ * with explicitly specified security attribute by CONTEXT = 'xxx' -+ * clause. We call the clause as a "security attribute modifier". -+ * -+ * The series of hooks enables the guest to handle the given -+ * security attribute and apply it on the specified database -+ * object. -+ * -+ * The guest can apply this feature on the following statement: -+ * -+ * CREATE DATABASE -+ * ALTER DATABASE -+ * CREATE TABLE -+ * ALTER TABLE
-+ * ALTER TABLE
ALTER -+ * CREATE FUNCTION -+ * ALTER FUNCTION -+ */ -+ -+/* -+ * pgaceGramSecurityItem -+ * -+ * This hook is invoked during parsing a give query from parser/gram.y, -+ * and it generates a DefElem object which holds explicitly specified -+ * security attribute. If the guest support the feature of security -+ * attribute modifier, this hook has to check whether the given clause -+ * is appropriate, or not. -+ * -+ * In the following exmaple case: -+ * CREATE TABLE tbl ( -+ * x integer, -+ * y text -+ * ) CONTEXT = 'system_u:object_r:sepgsql_ro_table_t:Classified', -+ * -+ * This hook is invoked with "context" as an argument of defname -+ * and "system_u:object_r:sepgsql_ro_table_t:Classified" as an -+ * argument of value, and has to check whether it is appropriate -+ * as a security attribute modifier, or not. -+ * If OK, the hook generates a DefElem object which contains -+ * the given context, and returns it. -+ * -+ * To return NULL means that "This clause is not a security attribute -+ * modifier", then it makes an error. -+ */ -+static inline DefElem * -+pgaceGramSecurityItem(char *defname, char *value) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlGramSecurityItem(defname, value); -+#endif -+ return NULL; -+} -+ -+/* -+ * pgaceIsGramSecurityItem -+ * -+ * This hook checks whether the given DefElem object means security -+ * attribute modifier generated at pgaceGramSecurityItem(), or not. -+ * If OK, it returns true. -+ */ -+static inline bool -+pgaceIsGramSecurityItem(DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlIsGramSecurityItem(defel); -+#endif -+ 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 security attribute modifier generated at -+ * pgaceGramSecurityItem(). -+ */ -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramCreateRelation(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at CREATE TABLE: unavailable"))); -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramCreateAttribute(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at CREATE TABLE column: unavailable"))); -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramAlterRelation(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at ALTER TABLE: unavailable"))); -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramAlterAttribute(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at ALTER TABLE column: unavailable"))); -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramCreateDatabase(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at CREATE DATABASE: unavailable"))); -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramAlterDatabase(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at ALTER DATABASE: unavailable"))); -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramCreateFunction(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at CREATE FUNCTION: unavailable"))); -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlGramAlterFunction(rel, tuple, defel); -+ return; -+ } -+#endif -+ if (defel) -+ ereport(ERROR, -+ (errcode(ERRCODE_PGACE_ERROR), -+ errmsg("security extention at ALTER FUNCTION: unavailable"))); -+} -+ -+/****************************************************************** -+ * 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. -+ */ -+static inline void -+pgaceSetDatabaseParam(const char *name, char *argstring) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlSetDatabaseParam(name, argstring); -+#endif -+} -+ -+/* -+ * pgaceGetDatabaseParam -+ * -+ * This hook is invoked just before reffering a GUC variable. -+ * -+ * arguments: -+ * - name is a name of GUC variable. -+ */ -+static inline void -+pgaceGetDatabaseParam(const char *name) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlGetDatabaseParam(name); -+#endif -+} -+ -+/****************************************************************** -+ * FUNCTION related hooks -+ ******************************************************************/ -+ -+/* -+ * pgaceCallFunction -+ * -+ * This hook is invoked just before execute a function as a part -+ * of the query. It provides a FmgrInfo object used to execute -+ * function, and the guest can store an opaque data within -+ * FmgrInfo::fn_pgaceItem. -+ */ -+static inline void -+pgaceCallFunction(FmgrInfo *finfo) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlCallFunction(finfo, false); -+#endif -+} -+ -+/* -+ * 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.) -+ * -+ * The guest can refer FmgrInfo and TriggerData object to make -+ * its decision. -+ */ -+static inline bool -+pgaceCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlCallFunctionTrigger(finfo, tgdata); -+#endif -+ return true; -+} -+ -+/* -+ * pgaceCallFunctionFastPath -+ * -+ * This hook is invoked just before executing a function in -+ * fast path. -+ */ -+static inline void -+pgaceCallFunctionFastPath(FmgrInfo *finfo) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlCallFunction(finfo, true); -+#endif -+} -+ -+/* -+ * 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(). -+ */ -+static inline Datum -+pgaceBeginPerformCheckFK(Relation rel, bool is_primary, Oid save_userid) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlBeginPerformCheckFK(rel, is_primary, save_userid); -+#endif -+ return PointerGetDatum(NULL); -+} -+ -+/* -+ * pgaceEndPerformCheckFK -+ * -+ * This hook is invoked just after performing FK constraint checks. -+ * The guest can restore its internal state using this hook. -+ */ -+static inline void -+pgaceEndPerformCheckFK(Relation rel, Datum save_pgace) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlEndPerformCheckFK(rel, save_pgace); -+#endif -+} -+ -+/****************************************************************** -+ * 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. -+ */ -+static inline void -+pgaceLockTable(Oid relid) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLockTable(relid); -+#endif -+} -+ -+/****************************************************************** -+ * 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 -+ */ -+static inline void -+pgaceCopyTable(Relation rel, List *attNumList, bool isFrom) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlCopyTable(rel, attNumList, isFrom); -+#endif -+} -+ -+/* -+ * 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 -+ */ -+static inline void -+pgaceCopyFile(Relation rel, int fdesc, const char *filename, bool isFrom) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlCopyFile(rel, fdesc, filename, isFrom); -+#endif -+} -+ -+/* -+ * 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 -+ */ -+static inline bool -+pgaceCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlCopyToTuple(rel, attNumList, tuple); -+#endif -+ return true; -+} -+ -+/****************************************************************** + * Loadable shared library module hooks -+ ******************************************************************/ ++ */ ++extern void pgaceLoadSharedModule(const char *filename); + +/* -+ * 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. ++ * Binary Large Object hooks + */ -+static inline void -+pgaceLoadSharedModule(const char *filename) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLoadSharedModule(filename); -+#endif -+} -+ -+/****************************************************************** -+ * Binary Large Object (BLOB) 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); +/* -+ * 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. -+ */ -+static inline void -+pgaceLargeObjectCreate(Relation rel, HeapTuple tuple) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLargeObjectCreate(rel, tuple); -+#endif -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceLargeObjectDrop(Relation rel, HeapTuple tuple, void **pgaceItem) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLargeObjectDrop(rel, tuple, pgaceItem); -+#endif -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceLargeObjectRead(LargeObjectDesc *lodesc, int length) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLargeObjectRead(lodesc, length); -+#endif -+} -+ -+/* -+ * pgaceLargeObjectWrite -+ * -+ * This hook is invoked at the head of lo_write(). -+ */ -+static inline void -+pgaceLargeObjectWrite(LargeObjectDesc *lodesc, int length) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLargeObjectWrite(lodesc, length); -+#endif -+} -+ -+/* -+ * pgaceLargeObjectTruncate -+ * -+ * This hook is invoked at the head of lo_truncate(). -+ */ -+static inline void -+pgaceLargeObjectTruncate(LargeObjectDesc *lodesc, int offset) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLargeObjectTruncate(lodesc, offset); -+#endif -+} -+ -+/* -+ * pgaceLargeObjectImport -+ * -+ * This hook is invoked just before importing the given file. -+ */ -+static inline void -+pgaceLargeObjectImport(Oid loid, int fdesc, const char *filename) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLargeObjectImport(loid, fdesc, filename); -+#endif -+} -+ -+/* -+ * pgaceLargeObjectExport -+ * -+ * This hook is invoked just before exporting the given large object. -+ */ -+static inline void -+pgaceLargeObjectExport(Oid loid, int fdesc, const char *filename) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ sepgsqlLargeObjectExport(loid, fdesc, filename); -+#endif -+} -+ -+/* -+ * 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. -+ */ -+static inline void -+pgaceLargeObjectGetSecurity(Relation rel, HeapTuple tuple) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlLargeObjectGetSecurity(rel, tuple); -+ return; -+ } -+#endif -+ elog(ERROR, "PGACE: There is no guest module 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. -+ */ -+static inline void -+pgaceLargeObjectSetSecurity(Relation rel, HeapTuple newtup, HeapTuple oldtup) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ { -+ sepgsqlLargeObjectSetSecurity(rel, newtup, oldtup); -+ return; -+ } -+#endif -+ elog(ERROR, "PGACE: There is no guest module available."); -+} -+ -+/****************************************************************** + * Security Label hooks -+ ******************************************************************/ ++ */ ++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); + +/* -+ * pgaceSecurityAttributeNecessary -+ * -+ * This hook provides a hint to the heap input/output subsystem. -+ * If it returns true, sizeof(Oid) bytes are expanded in HeapTupleHeader -+ * to store security identifier. ++ * PGACE common facilities (not hooks) + */ -+static inline bool -+pgaceSecurityAttributeNecessary(void) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return true; -+#endif -+ 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" -+ */ -+static inline char * -+pgaceTranslateSecurityLabelIn(char *seclabel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlTranslateSecurityLabelIn(seclabel); -+#endif -+ 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. -+ */ -+static inline char * -+pgaceTranslateSecurityLabelOut(char *seclabel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlTranslateSecurityLabelOut(seclabel); -+#endif -+ return seclabel; -+} -+ -+/* -+ * pgaceValidateSecurityLabel -+ * -+ * This hook enables the guest to validate the given security attribute -+ * in raw-internal format. If it is not available, the hook has to -+ * return an alternative security attribute. -+ */ -+static inline bool -+pgaceCheckValidSecurityLabel(char *seclabel) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlCheckValidSecurityLabel(seclabel); -+#endif -+ 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. -+ */ -+static inline char * -+pgaceUnlabeledSecurityLabel(void) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlUnlabeledSecurityLabel(); -+#endif -+ 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. -+ */ -+static inline char * -+pgaceSecurityLabelOfLabel(void) -+{ -+#if defined(HAVE_SELINUX) -+ if (sepgsqlIsEnabled()) -+ return sepgsqlSecurityLabelOfLabel(); -+#endif -+ return NULL; -+} -+ -+/****************************************************************** -+ * PGACE common facilities (not a hooks) -+ ******************************************************************/ -+ -+/* GUC parameter support */ -+extern const char *pgaceShowSecurityFeature(void); -+ -+/* Security Label Management */ ++/* security label management */ +extern void pgacePostBootstrapingMode(void); + -+extern Oid pgaceSecurityLabelToSid(char *label); -+ -+extern char *pgaceSidToSecurityLabel(Oid security_id); -+ +extern Oid pgaceLookupSecurityId(char *label); + -+extern char *pgaceLookupSecurityLabel(Oid security_id); ++extern char *pgaceLookupSecurityLabel(Oid sid); + -+/* Extended SQL statements related */ ++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 *pgace_attr_list); ++ List *pgaceAttrList); +extern void pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple, -+ List *pgace_attr_list); ++ List *pgaceAttrList); +extern void pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd); + ++/* Export security system columns */ ++extern Datum pgaceHeapGetSecurityLabelSysattr(HeapTuple tuple); ++ +/****************************************************************** + * Ported utility functions from 8.4devel + ******************************************************************/ @@ -11328,13 +12355,17 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +#define TextDatumGetCString(x) \ + (DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(x)))) + ++extern const char *pgaceAssignFeatureString(const char *value, bool doit, GucSource source); ++ +/****************************************************************** + * SQL function declaration related to PGACE security framework + ******************************************************************/ + +/* -+ * SE-PostgreSQL SQL FUNCTIONS ++ * 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); @@ -11349,8 +12380,8 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +#endif // PGACE_H diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h --- base/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/include/security/sepgsql.h 2008-10-31 17:01:56.000000000 +0900 -@@ -0,0 +1,221 @@ ++++ sepgsql/src/include/security/sepgsql.h 2009-01-21 17:26:07.000000000 +0900 +@@ -0,0 +1,244 @@ +/* + * src/include/security/sepgsql.h + * headers for Security-Enhanced PostgreSQL (SE-PostgreSQL) @@ -11362,14 +12393,6 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep +#ifndef SEPGSQL_H +#define SEPGSQL_H + -+/* system catalogs */ -+#include "catalog/pg_security.h" -+#include "lib/stringinfo.h" -+#include "nodes/execnodes.h" -+#include "nodes/nodes.h" -+#include "nodes/params.h" -+#include "nodes/parsenodes.h" -+ +#include +#include +#include @@ -11377,20 +12400,35 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep +/* + * SE-PostgreSQL modes + */ -+extern char *sepostgresql_mode; ++typedef enum ++{ ++ SEPGSQL_MODE_DEFAULT, ++ SEPGSQL_MODE_ENFORCING, ++ SEPGSQL_MODE_PERMISSIVE, ++ SEPGSQL_MODE_DISABLED, ++} SepgsqlModeType; ++ ++extern int sepostgresql_mode; ++extern char *sepostgresql_mode_string; ++extern bool sepostgresql_row_level; ++ ++extern const char *sepgsqlAssignModeString(const char *value, bool doit, GucSource source); + +/* -+ * Permission codes of internal representation ++ * 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 << 0) -+#define SEPGSQL_PERMS_SELECT (1UL << 1) -+#define SEPGSQL_PERMS_UPDATE (1UL << 2) -+#define SEPGSQL_PERMS_INSERT (1UL << 3) -+#define SEPGSQL_PERMS_DELETE (1UL << 4) -+#define SEPGSQL_PERMS_RELABELFROM (1UL << 5) -+#define SEPGSQL_PERMS_RELABELTO (1UL << 6) -+#define SEPGSQL_PERMS_READ (1UL << 7) -+#define SEPGSQL_PERMS_WRITE (1UL << 8) ++#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 @@ -11404,11 +12442,9 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep +extern pid_t sepgsqlStartupWorkerProcess(void); + +/* SQL proxy hooks */ -+extern List *sepgsqlProxyQuery(List *queryList); ++extern List *sepgsqlPostQueryRewrite(List *queryList); + -+extern void sepgsqlVerifyQuery(PlannedStmt *pstmt, int eflags); -+ -+extern void sepgsqlEvaluateParams(List *params); ++extern void sepgsqlExecutorStart(QueryDesc *queryDesc, int eflags); + +extern void sepgsqlProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel); + @@ -11425,8 +12461,6 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep + bool is_internal, bool with_returning); + +/* Extended SQL statement hooks */ -+extern DefElem *sepgsqlGramSecurityItem(char *defname, char *value); -+ +extern bool sepgsqlIsGramSecurityItem(DefElem *defel); + +extern void sepgsqlGramCreateRelation(Relation rel, HeapTuple tuple, @@ -11452,17 +12486,23 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep +extern void sepgsqlGetDatabaseParam(const char *name); + +/* FUNCTION related hooks */ -+extern void sepgsqlCallFunction(FmgrInfo *finfo, bool with_perm_check); ++extern void sepgsqlCallFunction(FmgrInfo *finfo); + -+extern bool sepgsqlCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata); ++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 */ @@ -11495,6 +12535,8 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep +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); @@ -11565,12 +12607,24 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep + */ +extern const char *sepgsqlTupleName(Oid relid, HeapTuple tuple); + -+extern security_class_t sepgsqlProperFileObjectClass(int fdesc, const char *filename); ++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 oldtup, uint32 perms, bool abort); ++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 -rpNU3 base/src/include/storage/fd.h sepgsql/src/include/storage/fd.h --- base/src/include/storage/fd.h 2008-01-07 23:51:33.000000000 +0900 @@ -11607,16 +12661,16 @@ diff -rpNU3 base/src/include/utils/catcache.h sepgsql/src/include/utils/catcache Datum v1, Datum v2, diff -rpNU3 base/src/include/utils/errcodes.h sepgsql/src/include/utils/errcodes.h --- base/src/include/utils/errcodes.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/utils/errcodes.h 2008-06-14 02:36:58.000000000 +0900 ++++ sepgsql/src/include/utils/errcodes.h 2008-12-02 11:39:45.000000000 +0900 @@ -339,6 +339,12 @@ #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_SELINUX_ERROR MAKE_SQLSTATE('S','E', '0','0','1') -+#define ERRCODE_SELINUX_AUDIT MAKE_SQLSTATE('S','E', '0','0','2') -+#define ERRCODE_SELINUX_INFO MAKE_SQLSTATE('S','E', '0','0','3') ++#define ERRCODE_SELINUX_ERROR MAKE_SQLSTATE('S','E', '0','1','1') ++#define ERRCODE_SELINUX_AUDIT MAKE_SQLSTATE('S','E', '0','1','2') ++#define ERRCODE_SELINUX_INFO MAKE_SQLSTATE('S','E', '0','1','3') + /* Class XX - Internal Error (PostgreSQL-specific error class) */ /* (this is for "can't-happen" conditions and software bugs) */ @@ -11642,3 +12696,23 @@ diff -rpNU3 base/src/include/utils/syscache.h sepgsql/src/include/utils/syscache /* convenience routines */ extern HeapTuple SearchSysCacheCopy(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4); +diff -rpNU3 base/src/test/regress/expected/sanity_check.out sepgsql/src/test/regress/expected/sanity_check.out +--- base/src/test/regress/expected/sanity_check.out 2007-11-25 12:49:12.000000000 +0900 ++++ sepgsql/src/test/regress/expected/sanity_check.out 2008-11-24 19:46:15.000000000 +0900 +@@ -111,6 +111,7 @@ SELECT relname, relhasindex + pg_pltemplate | t + pg_proc | t + pg_rewrite | t ++ pg_security | t + pg_shdepend | t + pg_shdescription | t + pg_statistic | t +@@ -149,7 +150,7 @@ SELECT relname, relhasindex + timetz_tbl | f + tinterval_tbl | f + varchar_tbl | f +-(138 rows) ++(139 rows) + + -- + -- another sanity check: every system catalog that has OIDs should have diff --git a/sepostgresql.init b/sepostgresql.init index fd339b9..9f49dee 100644 --- a/sepostgresql.init +++ b/sepostgresql.init @@ -7,9 +7,9 @@ # pidfile: /var/run/postmaster.pid #--------------------------------------------------------------------- -PGVERSION="8.3.5" +PGVERSION="8.3.6" PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` -SEPGVERSION="2.1183" +SEPGVERSION="2.1518" # source function library . /etc/rc.d/init.d/functions @@ -38,7 +38,7 @@ export SEPGSQL_FALLBACK_CONTEXT # Check that networking is up. test "${NETWORKING}" = "no" && exit 0 -test -f "${SEPGSQL_BIN}/postmaster" || exit 1 +test -f "${SEPGSQL_BIN}/sepostgres" || exit 1 script_result=0 @@ -165,7 +165,7 @@ do_initdb() { test -x /sbin/restorecon && /sbin/restorecon -R "${SEPGSQL_DATA}" # Initialize the database cd ${SEPGSQL_BIN} - /sbin/runuser -- sepgsql -c "./initdb.sepgsql -A 'ident sameuser' ${SEPGSQL_DATA}" \ + /sbin/runuser -- sepgsql -c "./initdb.sepgsql --pgace-feature=selinux -A 'ident sameuser' ${SEPGSQL_DATA}" \ >> "${SEPGSQL_STARTUP_LOG}" 2>&1 < /dev/null if [ -f "${SEPGSQL_DATA}/PG_VERSION" ]; then echo_success diff --git a/sepostgresql.spec b/sepostgresql.spec index f02b700..58d42d2 100644 --- a/sepostgresql.spec +++ b/sepostgresql.spec @@ -21,8 +21,8 @@ Summary: Security Enhanced PostgreSQL Name: sepostgresql -Version: 8.3.5 -Release: 2.1183%{?sepgsql_extension}%{?dist} +Version: 8.3.6 +Release: 2.1518%{?sepgsql_extension}%{?dist} License: BSD Group: Applications/Databases Url: http://code.google.com/p/sepgsql/ @@ -31,9 +31,9 @@ Source0: ftp://ftp.postgresql.org/pub/source/v%{version}/postgresql-%{version}.t Source1: sepostgresql.init Source2: sepostgresql.8 Source3: sepostgresql.logrotate -Patch0: sepostgresql-sepgsql-8.3.5-2.patch -Patch1: sepostgresql-policy-8.3.5-2.patch -Patch2: sepostgresql-pg_dump-8.3.5-2.patch +Patch0: sepostgresql-sepgsql-8.3.6-2.patch +Patch1: sepostgresql-policy-8.3.6-2.patch +Patch2: sepostgresql-pg_dump-8.3.6-2.patch Patch3: sepostgresql-fedora-prefix.patch BuildRequires: perl glibc-devel bison flex readline-devel zlib-devel >= 1.0.4 BuildRequires: checkpolicy libselinux-devel >= 2.0.43 @@ -214,6 +214,10 @@ fi %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups %changelog +* Fri Feb 6 2009 - 8.3.6-2.1518 +- upgrade base PostgreSQL version 8.3.5->8.3.6 +- backport features from 8.4devel tree + * Wed Nov 5 2008 - 8.3.5-2.1182 - upgrade base PostgreSQL version 8.3.4->8.3.5 - backport cumulative bugfixes from 8.4devel series diff --git a/sources b/sources index 5fbd3e3..de64848 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -3bc028774d7a79e926be0c6a9c7ca209 postgresql-8.3.5.tar.bz2 +4f8c67d802bd03b5b844e268bba7d44a postgresql-8.3.6.tar.bz2 From 640edf5fd46313f27ed9972887baae18ed3363b3 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Thu, 26 Feb 2009 12:28:47 +0000 Subject: [PATCH 3/7] bugfix: possible information leak by the order of permission checks in row level permission checks. --- sepostgresql-policy-8.3.6-2.patch | 2 +- sepostgresql-sepgsql-8.3.6-2.patch | 560 +++++++++++++---------------- sepostgresql.init | 2 +- sepostgresql.spec | 27 +- 4 files changed, 271 insertions(+), 320 deletions(-) diff --git a/sepostgresql-policy-8.3.6-2.patch b/sepostgresql-policy-8.3.6-2.patch index 067e34f..fe5e8f3 100644 --- a/sepostgresql-policy-8.3.6-2.patch +++ b/sepostgresql-policy-8.3.6-2.patch @@ -103,7 +103,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.if sepgs +## There are no interface declaration diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te --- base/src/backend/security/sepgsql/policy/sepostgresql-devel.te 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-01-20 16:35:05.000000000 +0900 ++++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-02-26 21:22:49.000000000 +0900 @@ -0,0 +1,120 @@ +policy_module(sepostgresql-devel, 3.23) + diff --git a/sepostgresql-sepgsql-8.3.6-2.patch b/sepostgresql-sepgsql-8.3.6-2.patch index b036880..db32fe5 100644 --- a/sepostgresql-sepgsql-8.3.6-2.patch +++ b/sepostgresql-sepgsql-8.3.6-2.patch @@ -2804,7 +2804,7 @@ diff -rpNU3 base/src/backend/executor/execQual.c sepgsql/src/backend/executor/ex /* diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/execScan.c --- base/src/backend/executor/execScan.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/executor/execScan.c 2008-12-28 01:06:59.000000000 +0900 ++++ sepgsql/src/backend/executor/execScan.c 2009-02-25 22:31:25.000000000 +0900 @@ -20,6 +20,7 @@ #include "executor/executor.h" @@ -2813,61 +2813,40 @@ diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/ex #include "utils/memutils.h" -@@ -48,7 +49,7 @@ TupleTableSlot * - ExecScan(ScanState *node, - ExecScanAccessMtd accessMtd) /* function returning a tuple */ - { -- ExprContext *econtext; -+ ExprContext *econtext = node->ps.ps_ExprContext; - List *qual; +@@ -53,6 +54,7 @@ ExecScan(ScanState *node, ProjectionInfo *projInfo; ExprDoneCond isDone; -@@ -65,7 +66,22 @@ ExecScan(ScanState *node, + TupleTableSlot *resultSlot; ++ Scan *scan = (Scan *)node->ps.plan; + + /* + * Fetch data from node +@@ -64,7 +66,7 @@ ExecScan(ScanState *node, + * If we have neither a qual to check nor a projection to do, just skip * all the overhead and return the raw scan tuple. */ - if (!qual && !projInfo) -- return (*accessMtd) (node); -+ { -+ while (true) -+ { -+ resultSlot = (*accessMtd) (node); -+ -+ if (TupIsNull(resultSlot)) -+ break; -+ -+ if (pgaceExecScan((Scan *)node->ps.plan, -+ node->ss_currentRelation, resultSlot)) -+ break; -+ -+ ResetExprContext(econtext); -+ } -+ return resultSlot; -+ } +- if (!qual && !projInfo) ++ if (!qual && !projInfo && !scan->pgaceTuplePerms) + return (*accessMtd) (node); /* - * Check to see if we're still projecting out tuples from a previous scan -@@ -87,7 +103,6 @@ ExecScan(ScanState *node, - * 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); - - /* -@@ -127,8 +142,11 @@ ExecScan(ScanState *node, +@@ -127,9 +129,14 @@ ExecScan(ScanState *node, * 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)) -+ if ((!qual || ExecQual(qual, econtext, false)) -+ && pgaceExecScan((Scan *)node->ps.plan, -+ node->ss_currentRelation, slot)) ++ if (pgaceExecScan(scan, node->ss_currentRelation, slot, false) ++ && (!qual || ExecQual(qual, econtext, false))) { ++ /* special care for FK checks */ ++ pgaceExecScan(scan, node->ss_currentRelation, slot, true); ++ /* * Found a satisfactory scan tuple. -@@ -197,6 +215,7 @@ tlist_matches_tupdesc(PlanState *ps, Lis + */ +@@ -197,6 +204,7 @@ tlist_matches_tupdesc(PlanState *ps, Lis int numattrs = tupdesc->natts; int attrno; bool hasoid; @@ -2875,7 +2854,7 @@ diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/ex ListCell *tlist_item = list_head(tlist); /* Check the tlist attributes */ -@@ -240,12 +259,16 @@ tlist_matches_tupdesc(PlanState *ps, Lis +@@ -240,12 +248,16 @@ tlist_matches_tupdesc(PlanState *ps, Lis return false; /* tlist too long */ /* @@ -3133,7 +3112,7 @@ diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fss PG_RETURN_INT32(0); diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c --- base/src/backend/nodes/copyfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/nodes/copyfuncs.c 2009-01-21 17:02:57.000000000 +0900 ++++ sepgsql/src/backend/nodes/copyfuncs.c 2009-02-17 13:32:34.000000000 +0900 @@ -24,6 +24,7 @@ #include "nodes/plannodes.h" @@ -3190,7 +3169,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun return newnode; } -@@ -2998,6 +3005,26 @@ _copyValue(Value *from) +@@ -2998,6 +3005,25 @@ _copyValue(Value *from) return newnode; } @@ -3202,7 +3181,6 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun +_copySelinuxEvalItem(SelinuxEvalItem *from) +{ + SelinuxEvalItem *newnode = makeNode(SelinuxEvalItem); -+ int n; + + COPY_SCALAR_FIELD(relid); + COPY_SCALAR_FIELD(inh); @@ -3217,7 +3195,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun /* * copyObject * -@@ -3600,6 +3627,9 @@ copyObject(void *from) +@@ -3600,6 +3626,9 @@ copyObject(void *from) case T_XmlSerialize: retval = _copyXmlSerialize(from); break; @@ -4891,8 +4869,8 @@ diff -rpNU3 base/src/backend/security/pgaceCommon.c sepgsql/src/backend/security +#endif /* HAVE_SELINUX */ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/pgaceHooks.c --- base/src/backend/security/pgaceHooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/pgaceHooks.c 2009-01-21 17:26:07.000000000 +0900 -@@ -0,0 +1,1490 @@ ++++ sepgsql/src/backend/security/pgaceHooks.c 2009-02-25 22:31:25.000000000 +0900 +@@ -0,0 +1,1462 @@ +/* + * src/backend/security/pgaceHooks.c + * Security hooks in PostgreSQL Access Control Extension (PGACE) @@ -5125,6 +5103,27 @@ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/ +} + +/* ++ * pgaceRowlvBehaviorSwitchTo ++ * changes internal state during FK constraint checks ++ */ ++bool ++pgaceRowlvBehaviorSwitchTo(bool new_abort) ++{ ++ switch (pgace_feature) ++ { ++#ifdef HAVE_SELINUX ++ case PGACE_FEATURE_SELINUX: ++ if (sepgsqlIsEnabled()) ++ return sepgsqlRowlvBehaviorSwitchTo(new_abort); ++ break; ++#endif ++ default: ++ break; ++ } ++ return new_abort; ++} ++ ++/* + * pgaceExecScan + * + * This hook is invoked on ExecScan for each tuple fetched. @@ -5140,14 +5139,14 @@ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/ + * required to scanned tuples. + */ +bool -+pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot) ++pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort) +{ + switch (pgace_feature) + { +#ifdef HAVE_SELINUX + case PGACE_FEATURE_SELINUX: + if (sepgsqlIsEnabled()) -+ return sepgsqlExecScan(scan, rel, slot); ++ return sepgsqlExecScan(scan, rel, slot, abort); + break; +#endif + default: @@ -5751,55 +5750,6 @@ diff -rpNU3 base/src/backend/security/pgaceHooks.c sepgsql/src/backend/security/ +} + +/* -+ * 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 *pgace_private) -+{ -+ 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 pgace_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 @@ -8267,8 +8217,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/core.c sepgsql/src/backend/securit +} diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/security/sepgsql/hooks.c --- base/src/backend/security/sepgsql/hooks.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/hooks.c 2009-01-22 10:40:54.000000000 +0900 -@@ -0,0 +1,1018 @@ ++++ sepgsql/src/backend/security/sepgsql/hooks.c 2009-02-26 21:08:58.000000000 +0900 +@@ -0,0 +1,1160 @@ +/* + * src/backend/security/sepgsql/hooks.c + * implementations of PGACE framework @@ -8284,10 +8234,19 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +#include "access/skey.h" +#include "catalog/indexing.h" +#include "catalog/pg_aggregate.h" ++#include "catalog/pg_amproc.h" ++#include "catalog/pg_cast.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 "nodes/makefuncs.h" +#include "security/pgace.h" @@ -8673,6 +8632,148 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + return true; +} + ++/* ++ * 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,newtup,oldtup) \ ++ do { \ ++ if (!HeapTupleIsValid(oldtup)) \ ++ checkProcedureInstall(((Form_##catalog) GETSTRUCT(newtup))->member); \ ++ else if (((Form_##catalog) GETSTRUCT(newtup))->member \ ++ != ((Form_##catalog) GETSTRUCT(oldtup))->member) \ ++ checkProcedureInstall(((Form_##catalog) GETSTRUCT(oldtup))->member); \ ++ } while(0) ++ ++static void ++sepgsqlCheckProcedureInstall(Relation rel, HeapTuple newtup, HeapTuple oldtup) ++{ ++ /* ++ * 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, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggtransfn, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_aggregate, aggfinalfn, newtup, oldtup); ++ break; ++ ++ case AccessMethodRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_am, aminsert, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ambeginscan, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amgettuple, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amgetmulti, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amrescan, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amendscan, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ammarkpos, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amrestrpos, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ambuild, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, ambulkdelete, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amvacuumcleanup, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amcostestimate, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_am, amoptions, newtup, oldtup); ++ break; ++ ++ case AccessMethodProcedureRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_amproc, amproc, newtup, oldtup); ++ break; ++ ++ case CastRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_cast, castfunc, newtup, oldtup); ++ break; ++ ++ case ConversionRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_conversion, conproc, newtup, oldtup); ++ break; ++ ++ case LanguageRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_language, lanplcallfoid, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_language, lanvalidator, newtup, oldtup); ++ break; ++ ++ case OperatorRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprcode, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprrest, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_operator, oprjoin, newtup, oldtup); ++ break; ++ ++ case TriggerRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_trigger, tgfoid, newtup, oldtup); ++ break; ++ ++ case TSParserRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsstart, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prstoken, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsend, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prsheadline, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_parser, prslextype, newtup, oldtup); ++ break; ++ ++ case TSTemplateRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmplinit, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_ts_template, tmpllexize, newtup, oldtup); ++ break; ++ ++ case TypeRelationId: ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typinput, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typoutput, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typreceive, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typsend, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodin, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typmodout, newtup, oldtup); ++ CHECK_PROC_INSTALL_HANDLER(pg_type, typanalyze, newtup, oldtup); ++ break; ++ } ++} ++ +/******************************************************************************* + * LOAD shared library module hook + *******************************************************************************/ @@ -8942,11 +9043,24 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +static bool abort_on_violated_tuple = false; + +bool -+sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot) ++sepgsqlRowlvBehaviorSwitchTo(bool new_abort) ++{ ++ bool old_abort = abort_on_violated_tuple; ++ ++ abort_on_violated_tuple = new_abort; ++ ++ return old_abort; ++} ++ ++bool ++sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort) +{ + HeapTuple tuple; + uint32 perms = (scan->pgaceTuplePerms & SEPGSQL_PERMS_MASK); + ++ if (abort_on_violated_tuple != abort) ++ return true; /* no need to do here */ ++ + if (perms == 0) + return true; + @@ -8956,32 +9070,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + 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 + *******************************************************************************/ @@ -9186,9 +9274,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + uint32 perms; + -+ /* -+ * default context for no explicit labeled tuple -+ */ ++ sepgsqlCheckProcedureInstall(rel, tuple, NULL); ++ + if (!OidIsValid(HeapTupleGetSecLabel(tuple))) + { + /* @@ -9220,12 +9307,14 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +{ + Oid relid = RelationGetRelid(rel); + HeapTuple oldtup; -+ uint32 perms; ++ uint32 perms = 0; + bool rc = true; + bool relabel = false; + + oldtup = getHeapTupleFromItemPointer(rel, otid); + ++ sepgsqlCheckProcedureInstall(rel, newtup, oldtup); ++ + if (!OidIsValid(HeapTupleGetSecLabel(newtup))) + { + /* @@ -9251,7 +9340,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + sepgsqlTupleObjectClass(relid, newtup) != sepgsqlTupleObjectClass(relid, oldtup)) + relabel = true; + -+ perms = SEPGSQL_PERMS_UPDATE; ++ if (is_internal) ++ perms |= SEPGSQL_PERMS_UPDATE; + if (relabel) + perms |= SEPGSQL_PERMS_RELABELFROM; + rc = sepgsqlCheckTuplePerms(rel, oldtup, newtup, perms, is_internal); @@ -9275,11 +9365,13 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi + bool is_internal, bool with_returning) +{ + HeapTuple oldtup; -+ uint32 perms = SEPGSQL_PERMS_DELETE; ++ uint32 perms = 0; + bool rc; + + if (isTrustedRelation(rel, is_internal)) + return true; ++ if (is_internal) ++ perms |= SEPGSQL_PERMS_DELETE; + + oldtup = getHeapTupleFromItemPointer(rel, otid); + rc = sepgsqlCheckTuplePerms(rel, oldtup, NULL, perms, is_internal); @@ -9289,8 +9381,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/hooks.c sepgsql/src/backend/securi +} diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/security/sepgsql/permissions.c --- base/src/backend/security/sepgsql/permissions.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/permissions.c 2009-01-22 14:28:10.000000000 +0900 -@@ -0,0 +1,794 @@ ++++ sepgsql/src/backend/security/sepgsql/permissions.c 2009-02-26 21:08:58.000000000 +0900 +@@ -0,0 +1,636 @@ + +/* + * src/backend/security/sepgsql/permissions.c @@ -9305,23 +9397,10 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ +#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" @@ -9638,148 +9717,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + 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, amgetmulti, 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) @@ -9790,9 +9727,6 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ + + Assert(HeapTupleIsValid(tuple)); + -+ if ((perms & (SEPGSQL_PERMS_INSERT | SEPGSQL_PERMS_UPDATE)) != 0) -+ sepgsqlCheckProcedureInstall(rel, tuple, newtup); -+ + tclass = sepgsqlTupleObjectClass(RelationGetRelid(rel), tuple); + + switch (tclass) @@ -10087,8 +10021,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/permissions.c sepgsql/src/backend/ +} diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/security/sepgsql/proxy.c --- base/src/backend/security/sepgsql/proxy.c 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/proxy.c 2009-01-23 13:07:12.000000000 +0900 -@@ -0,0 +1,1074 @@ ++++ sepgsql/src/backend/security/sepgsql/proxy.c 2009-02-26 21:08:58.000000000 +0900 +@@ -0,0 +1,1076 @@ +/* + * src/backend/security/sepgsql/proxy.c + * Proxying the given Query trees via SE-PostgreSQL @@ -10208,6 +10142,8 @@ diff -rpNU3 base/src/backend/security/sepgsql/proxy.c sepgsql/src/backend/securi +{ + rte->pgaceTuplePerms |= (perms & DB_TABLE__USE ? SEPGSQL_PERMS_USE : 0); + rte->pgaceTuplePerms |= (perms & DB_TABLE__SELECT ? SEPGSQL_PERMS_SELECT : 0); ++ rte->pgaceTuplePerms |= (perms & DB_TABLE__UPDATE ? SEPGSQL_PERMS_UPDATE : 0); ++ rte->pgaceTuplePerms |= (perms & DB_TABLE__DELETE ? SEPGSQL_PERMS_DELETE : 0); + + return addEvalRelation(selist, rte->relid, rte->inh, perms); +} @@ -11252,7 +11188,7 @@ diff -rpNU3 base/src/backend/tcop/utility.c sepgsql/src/backend/tcop/utility.c /* diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/adt/ri_triggers.c --- base/src/backend/utils/adt/ri_triggers.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/utils/adt/ri_triggers.c 2008-12-28 01:06:59.000000000 +0900 ++++ sepgsql/src/backend/utils/adt/ri_triggers.c 2009-02-25 22:31:25.000000000 +0900 @@ -37,6 +37,7 @@ #include "parser/parse_coerce.h" #include "parser/parse_relation.h" @@ -11265,7 +11201,7 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a int spi_result; Oid save_userid; bool save_secdefcxt; -+ Datum pgace_private = 0; ++ bool save_pgace; Datum vals[RI_MAX_NUMKEYS * 2]; char nulls[RI_MAX_NUMKEYS * 2]; @@ -11278,7 +11214,7 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a - vals, nulls, - test_snapshot, crosscheck_snapshot, - false, false, limit); -+ pgaceBeginPerformCheckFK(query_rel, detectNewRows, save_userid, &pgace_private); ++ save_pgace = pgaceRowlvBehaviorSwitchTo(detectNewRows); + PG_TRY(); + { + /* Finally we can run the query. */ @@ -11289,11 +11225,11 @@ diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c sepgsql/src/backend/utils/a + } + PG_CATCH(); + { -+ pgaceEndPerformCheckFK(query_rel, pgace_private); ++ pgaceRowlvBehaviorSwitchTo(save_pgace); + PG_RE_THROW(); + } + PG_END_TRY(); -+ pgaceEndPerformCheckFK(query_rel, pgace_private); ++ pgaceRowlvBehaviorSwitchTo(save_pgace); /* Restore UID */ SetUserIdAndContext(save_userid, save_secdefcxt); @@ -12182,8 +12118,8 @@ diff -rpNU3 base/src/include/pg_config.h.in sepgsql/src/include/pg_config.h.in diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace.h --- base/src/include/security/pgace.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/include/security/pgace.h 2009-01-21 17:26:07.000000000 +0900 -@@ -0,0 +1,194 @@ ++++ sepgsql/src/include/security/pgace.h 2009-02-25 22:31:25.000000000 +0900 +@@ -0,0 +1,192 @@ +/* + * include/security/pgace.h + * headers for PostgreSQL Access Control Extension (PGACE) @@ -12246,7 +12182,8 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +/* + * HeapTuple input/output hooks + */ -+extern bool pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot); ++extern bool pgaceRowlvBehaviorSwitchTo(bool new_abort); ++extern bool pgaceExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort); +extern bool pgaceHeapTupleInsert(Relation rel, HeapTuple tuple, + bool is_internal, bool with_returning); +extern bool pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup, @@ -12272,9 +12209,6 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +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 *pgace_private); -+extern void pgaceEndPerformCheckFK(Relation rel, Datum pgace_private); +extern bool pgaceAllowFunctionInlined(Oid fnoid, HeapTuple func_tuple); + +/* @@ -12380,8 +12314,8 @@ diff -rpNU3 base/src/include/security/pgace.h sepgsql/src/include/security/pgace +#endif // PGACE_H diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sepgsql.h --- base/src/include/security/sepgsql.h 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/include/security/sepgsql.h 2009-01-21 17:26:07.000000000 +0900 -@@ -0,0 +1,244 @@ ++++ sepgsql/src/include/security/sepgsql.h 2009-02-25 22:31:25.000000000 +0900 +@@ -0,0 +1,242 @@ +/* + * src/include/security/sepgsql.h + * headers for Security-Enhanced PostgreSQL (SE-PostgreSQL) @@ -12449,7 +12383,9 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep +extern void sepgsqlProcessUtility(Node *parsetree, ParamListInfo params, bool isTopLevel); + +/* ExecScan hooks */ -+extern bool sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot); ++extern bool sepgsqlExecScan(Scan *scan, Relation rel, TupleTableSlot *slot, bool abort); ++ ++extern bool sepgsqlRowlvBehaviorSwitchTo(bool new_abort); + +/* HeapTuple modification hooks */ +extern bool sepgsqlHeapTupleInsert(Relation rel, HeapTuple tuple, @@ -12492,10 +12428,6 @@ diff -rpNU3 base/src/include/security/sepgsql.h sepgsql/src/include/security/sep + +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 */ diff --git a/sepostgresql.init b/sepostgresql.init index 9f49dee..dfa42e4 100644 --- a/sepostgresql.init +++ b/sepostgresql.init @@ -9,7 +9,7 @@ PGVERSION="8.3.6" PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` -SEPGVERSION="2.1518" +SEPGVERSION="2.1634" # source function library . /etc/rc.d/init.d/functions diff --git a/sepostgresql.spec b/sepostgresql.spec index 58d42d2..cccb86e 100644 --- a/sepostgresql.spec +++ b/sepostgresql.spec @@ -22,7 +22,7 @@ Summary: Security Enhanced PostgreSQL Name: sepostgresql Version: 8.3.6 -Release: 2.1518%{?sepgsql_extension}%{?dist} +Release: 2.1634%{?sepgsql_extension}%{?dist} License: BSD Group: Applications/Databases Url: http://code.google.com/p/sepgsql/ @@ -88,21 +88,24 @@ CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS # parallel build, if possible make %{?_smp_mflags} -# to create empty .fc file +%if !%{fedora9} touch src/backend/security/sepgsql/policy/sepostgresql-devel.fc make -C src/backend/security/sepgsql/policy +%endif %install rm -rf %{buildroot} make DESTDIR=%{buildroot} install +%if !%{fedora9} for store in %{selinux_policy_stores} do install -d %{buildroot}%{_datadir}/selinux/${store} install -p -m 644 src/backend/security/sepgsql/policy/sepostgresql-devel.pp.${store} \ %{buildroot}%{_datadir}/selinux/${store}/sepostgresql-devel.pp done +%endif # avoid to conflict with native postgresql package mv %{buildroot}%{_bindir} %{buildroot}%{_bindir}.orig @@ -152,14 +155,17 @@ exit 0 /sbin/chkconfig --add %{name} /sbin/ldconfig +%if !%{fedora9} for store in %{selinux_policy_stores} do + # clean up legacy policy module (now it is unnecessary) %{_sbindir}/semodule -s ${store} -r sepostgresql >& /dev/null || : - if %{_sbindir}/semodule -s ${store} -l | grep -Eq "^sepostgresql-devel"; then + if %{_sbindir}/semodule -s ${store} -l 2>/dev/null | grep -Eq "^sepostgresql-devel"; then %{_sbindir}/semodule -s ${store} \ -i %{_datadir}/selinux/${store}/sepostgresql-devel.pp >& /dev/null || : fi done +%endif # Fix up non-standard file contexts /sbin/fixfiles -R %{name} restore || : @@ -208,15 +214,28 @@ fi %{_datadir}/sepgsql/conversion_create.sql %{_datadir}/sepgsql/information_schema.sql %{_datadir}/sepgsql/sql_features.txt +%if !%{fedora9} %attr(644,root,root) %{_datadir}/selinux/*/sepostgresql-devel.pp +%endif %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/data %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups %changelog -* Fri Feb 6 2009 - 8.3.6-2.1518 +* Thu Feb 26 2009 KaiGai Kohei - 8.3.6-2.1635 +- bugfix: possible information leak by the order of permission checks + in row level permission checks. + +* Wed Feb 25 2009 Fedora Release Engineering - 8.3.6-3.1518 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Feb 6 2009 - 8.3.6-2.1523 - upgrade base PostgreSQL version 8.3.5->8.3.6 - backport features from 8.4devel tree +- security policy fix for Fedora 9 + +* Sat Jan 17 2009 Tomas Mraz - 8.3.5-2.1183 +- rebuild with new openssl * Wed Nov 5 2008 - 8.3.5-2.1182 - upgrade base PostgreSQL version 8.3.4->8.3.5 From 9c31ac1a07dace75d1883b91173382739a84f988 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Fri, 27 Mar 2009 03:48:13 +0000 Subject: [PATCH 4/7] upgrade base PostgreSQL version 8.3.6->8.3.7 --- .cvsignore | 2 +- ...atch => sepostgresql-pg_dump-8.3.7-2.patch | 0 ...patch => sepostgresql-policy-8.3.7-2.patch | 2 +- ...atch => sepostgresql-sepgsql-8.3.7-2.patch | 48 +++++++++---------- sepostgresql.init | 4 +- sepostgresql.spec | 15 +++--- sources | 2 +- 7 files changed, 38 insertions(+), 35 deletions(-) rename sepostgresql-pg_dump-8.3.6-2.patch => sepostgresql-pg_dump-8.3.7-2.patch (100%) rename sepostgresql-policy-8.3.6-2.patch => sepostgresql-policy-8.3.7-2.patch (99%) rename sepostgresql-sepgsql-8.3.6-2.patch => sepostgresql-sepgsql-8.3.7-2.patch (99%) diff --git a/.cvsignore b/.cvsignore index a91c3f6..e18d446 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -postgresql-8.3.6.tar.bz2 +postgresql-8.3.7.tar.bz2 diff --git a/sepostgresql-pg_dump-8.3.6-2.patch b/sepostgresql-pg_dump-8.3.7-2.patch similarity index 100% rename from sepostgresql-pg_dump-8.3.6-2.patch rename to sepostgresql-pg_dump-8.3.7-2.patch diff --git a/sepostgresql-policy-8.3.6-2.patch b/sepostgresql-policy-8.3.7-2.patch similarity index 99% rename from sepostgresql-policy-8.3.6-2.patch rename to sepostgresql-policy-8.3.7-2.patch index fe5e8f3..7404657 100644 --- a/sepostgresql-policy-8.3.6-2.patch +++ b/sepostgresql-policy-8.3.7-2.patch @@ -103,7 +103,7 @@ diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.if sepgs +## There are no interface declaration diff -rpNU3 base/src/backend/security/sepgsql/policy/sepostgresql-devel.te sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te --- base/src/backend/security/sepgsql/policy/sepostgresql-devel.te 1970-01-01 09:00:00.000000000 +0900 -+++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-02-26 21:22:49.000000000 +0900 ++++ sepgsql/src/backend/security/sepgsql/policy/sepostgresql-devel.te 2009-02-26 21:30:17.000000000 +0900 @@ -0,0 +1,120 @@ +policy_module(sepostgresql-devel, 3.23) + diff --git a/sepostgresql-sepgsql-8.3.6-2.patch b/sepostgresql-sepgsql-8.3.7-2.patch similarity index 99% rename from sepostgresql-sepgsql-8.3.6-2.patch rename to sepostgresql-sepgsql-8.3.7-2.patch index db32fe5..ef2c562 100644 --- a/sepostgresql-sepgsql-8.3.6-2.patch +++ b/sepostgresql-sepgsql-8.3.7-2.patch @@ -1,6 +1,6 @@ diff -rpNU3 base/configure sepgsql/configure ---- base/configure 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/configure 2009-02-02 11:58:34.000000000 +0900 +--- base/configure 2009-03-15 17:47:25.000000000 +0900 ++++ sepgsql/configure 2009-03-15 17:53:20.000000000 +0900 @@ -314,7 +314,7 @@ ac_includes_default="\ # include #endif" @@ -143,8 +143,8 @@ diff -rpNU3 base/configure sepgsql/configure s,@ELF_SYS@,$ELF_SYS,;t t s,@LDFLAGS_SL@,$LDFLAGS_SL,;t t diff -rpNU3 base/configure.in sepgsql/configure.in ---- base/configure.in 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/configure.in 2009-02-02 11:58:34.000000000 +0900 +--- base/configure.in 2009-03-15 17:47:25.000000000 +0900 ++++ sepgsql/configure.in 2009-03-15 17:53:20.000000000 +0900 @@ -626,6 +626,19 @@ PGAC_ARG_BOOL(with, zlib, yes, AC_SUBST(with_zlib) @@ -1367,8 +1367,8 @@ diff -rpNU3 base/src/backend/catalog/catalog.c sepgsql/src/backend/catalog/catal relationId == SharedDependDependerIndexId || relationId == SharedDependReferenceIndexId || diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c ---- base/src/backend/catalog/heap.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/catalog/heap.c 2008-12-28 01:06:59.000000000 +0900 +--- base/src/backend/catalog/heap.c 2009-03-15 17:47:25.000000000 +0900 ++++ sepgsql/src/backend/catalog/heap.c 2009-03-15 17:53:20.000000000 +0900 @@ -53,6 +53,7 @@ #include "parser/parse_coerce.h" #include "parser/parse_expr.h" @@ -1387,7 +1387,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c static Oid AddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, -@@ -144,7 +146,13 @@ static FormData_pg_attribute a7 = { +@@ -145,7 +147,13 @@ static FormData_pg_attribute a7 = { true, 'p', 'i', true, false, false, true, 0 }; @@ -1402,7 +1402,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c /* * This function returns a Form_pg_attribute pointer for a system attribute. -@@ -184,6 +192,18 @@ SystemAttributeByName(const char *attnam +@@ -185,6 +193,18 @@ SystemAttributeByName(const char *attnam return NULL; } @@ -1421,7 +1421,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c /* ---------------------------------------------------------------- * XXX END OF UGLY HARD CODED BADNESS XXX -@@ -467,7 +487,8 @@ AddNewAttributeTuples(Oid new_rel_oid, +@@ -468,7 +488,8 @@ AddNewAttributeTuples(Oid new_rel_oid, TupleDesc tupdesc, char relkind, bool oidislocal, @@ -1431,7 +1431,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { const Form_pg_attribute *dpp; int i; -@@ -500,8 +521,10 @@ AddNewAttributeTuples(Oid new_rel_oid, +@@ -501,8 +522,10 @@ AddNewAttributeTuples(Oid new_rel_oid, tup = heap_addheader(Natts_pg_attribute, false, @@ -1442,7 +1442,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c simple_heap_insert(rel, tup); -@@ -537,6 +560,7 @@ AddNewAttributeTuples(Oid new_rel_oid, +@@ -538,6 +561,7 @@ AddNewAttributeTuples(Oid new_rel_oid, tup = heap_addheader(Natts_pg_attribute, false, @@ -1450,7 +1450,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c ATTRIBUTE_TUPLE_SIZE, (void *) *dpp); attStruct = (Form_pg_attribute) GETSTRUCT(tup); -@@ -592,7 +616,8 @@ void +@@ -593,7 +617,8 @@ void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, @@ -1460,7 +1460,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { Form_pg_class rd_rel = new_rel_desc->rd_rel; Datum values[Natts_pg_class]; -@@ -642,12 +667,16 @@ InsertPgClassTuple(Relation pg_class_des +@@ -643,12 +668,16 @@ InsertPgClassTuple(Relation pg_class_des * be embarrassing to do this sort of thing in polite company. */ HeapTupleSetOid(tup, new_rel_oid); @@ -1477,7 +1477,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c heap_freetuple(tup); } -@@ -665,7 +694,8 @@ AddNewRelationTuple(Relation pg_class_de +@@ -666,7 +695,8 @@ AddNewRelationTuple(Relation pg_class_de Oid new_type_oid, Oid relowner, char relkind, @@ -1487,7 +1487,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { Form_pg_class new_rel_reltup; -@@ -725,7 +755,7 @@ AddNewRelationTuple(Relation pg_class_de +@@ -726,7 +756,7 @@ AddNewRelationTuple(Relation pg_class_de new_rel_desc->rd_att->tdtypeid = new_type_oid; /* Now build and insert the tuple */ @@ -1496,7 +1496,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c } -@@ -791,7 +821,8 @@ heap_create_with_catalog(const char *rel +@@ -794,7 +824,8 @@ heap_create_with_catalog(const char *rel int oidinhcount, OnCommitAction oncommit, Datum reloptions, @@ -1506,7 +1506,7 @@ diff -rpNU3 base/src/backend/catalog/heap.c sepgsql/src/backend/catalog/heap.c { Relation pg_class_desc; Relation new_rel_desc; -@@ -963,13 +994,20 @@ heap_create_with_catalog(const char *rel +@@ -968,13 +999,20 @@ heap_create_with_catalog(const char *rel new_type_oid, ownerid, relkind, @@ -2203,8 +2203,8 @@ diff -rpNU3 base/src/backend/commands/dbcommands.c sepgsql/src/backend/commands/ /* Update indexes */ diff -rpNU3 base/src/backend/commands/functioncmds.c sepgsql/src/backend/commands/functioncmds.c ---- base/src/backend/commands/functioncmds.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/commands/functioncmds.c 2008-06-14 02:36:58.000000000 +0900 +--- base/src/backend/commands/functioncmds.c 2009-03-15 17:47:25.000000000 +0900 ++++ sepgsql/src/backend/commands/functioncmds.c 2009-03-15 17:53:20.000000000 +0900 @@ -47,6 +47,7 @@ #include "miscadmin.h" #include "parser/parse_func.h" @@ -3517,8 +3517,8 @@ diff -rpNU3 base/src/backend/optimizer/util/relnode.c sepgsql/src/backend/optimi /* Check type of rtable entry */ switch (rte->rtekind) diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze.c ---- base/src/backend/parser/analyze.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/src/backend/parser/analyze.c 2009-02-02 11:58:34.000000000 +0900 +--- base/src/backend/parser/analyze.c 2009-03-15 17:47:25.000000000 +0900 ++++ sepgsql/src/backend/parser/analyze.c 2009-03-15 17:53:20.000000000 +0900 @@ -24,6 +24,7 @@ #include "postgres.h" @@ -3535,7 +3535,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze typedef struct -@@ -612,14 +614,15 @@ transformInsertStmt(ParseState *pstate, +@@ -616,14 +618,15 @@ transformInsertStmt(ParseState *pstate, Expr *expr = (Expr *) lfirst(lc); ResTarget *col; TargetEntry *tle; @@ -3553,7 +3553,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze qry->targetList = lappend(qry->targetList, tle); icols = lnext(icols); -@@ -717,6 +720,46 @@ transformInsertRow(ParseState *pstate, L +@@ -721,6 +724,46 @@ transformInsertRow(ParseState *pstate, L return result; } @@ -3600,7 +3600,7 @@ diff -rpNU3 base/src/backend/parser/analyze.c sepgsql/src/backend/parser/analyze /* * transformSelectStmt - -@@ -783,6 +826,7 @@ transformSelectStmt(ParseState *pstate, +@@ -787,6 +830,7 @@ transformSelectStmt(ParseState *pstate, if (stmt->intoClause) { qry->intoClause = stmt->intoClause; diff --git a/sepostgresql.init b/sepostgresql.init index dfa42e4..e09d4aa 100644 --- a/sepostgresql.init +++ b/sepostgresql.init @@ -7,9 +7,9 @@ # pidfile: /var/run/postmaster.pid #--------------------------------------------------------------------- -PGVERSION="8.3.6" +PGVERSION="8.3.7" PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` -SEPGVERSION="2.1634" +SEPGVERSION="2.1770" # source function library . /etc/rc.d/init.d/functions diff --git a/sepostgresql.spec b/sepostgresql.spec index cccb86e..94493fa 100644 --- a/sepostgresql.spec +++ b/sepostgresql.spec @@ -21,8 +21,8 @@ Summary: Security Enhanced PostgreSQL Name: sepostgresql -Version: 8.3.6 -Release: 2.1634%{?sepgsql_extension}%{?dist} +Version: 8.3.7 +Release: 2.1770%{?sepgsql_extension}%{?dist} License: BSD Group: Applications/Databases Url: http://code.google.com/p/sepgsql/ @@ -31,9 +31,9 @@ Source0: ftp://ftp.postgresql.org/pub/source/v%{version}/postgresql-%{version}.t Source1: sepostgresql.init Source2: sepostgresql.8 Source3: sepostgresql.logrotate -Patch0: sepostgresql-sepgsql-8.3.6-2.patch -Patch1: sepostgresql-policy-8.3.6-2.patch -Patch2: sepostgresql-pg_dump-8.3.6-2.patch +Patch0: sepostgresql-sepgsql-8.3.7-2.patch +Patch1: sepostgresql-policy-8.3.7-2.patch +Patch2: sepostgresql-pg_dump-8.3.7-2.patch Patch3: sepostgresql-fedora-prefix.patch BuildRequires: perl glibc-devel bison flex readline-devel zlib-devel >= 1.0.4 BuildRequires: checkpolicy libselinux-devel >= 2.0.43 @@ -193,7 +193,7 @@ fi %files %defattr(-,root,root,-) -%doc COPYRIGHT README HISTORY +%doc COPYRIGHT README %{_initrddir}/sepostgresql %{_sysconfdir}/logrotate.d/sepostgresql %{_bindir}/initdb.sepgsql @@ -222,6 +222,9 @@ fi %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups %changelog +* Fri Mar 27 2009 KaiGai Kohei - 8.3.7-2.1770 +- upgrade base PostgreSQL version 8.3.6->8.3.7 + * Thu Feb 26 2009 KaiGai Kohei - 8.3.6-2.1635 - bugfix: possible information leak by the order of permission checks in row level permission checks. diff --git a/sources b/sources index de64848..7a88da9 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -4f8c67d802bd03b5b844e268bba7d44a postgresql-8.3.6.tar.bz2 +7b7e91a2221e55fe1b167e663217a96d postgresql-8.3.7.tar.bz2 From c443499dc0052ec9374bab297fa9885e4c83e895 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Thu, 10 Sep 2009 12:19:48 +0000 Subject: [PATCH 5/7] upgrade base PostgreSQL v8.3.7->8.3.8 --- .cvsignore | 2 +- ...atch => sepostgresql-pg_dump-8.3.8-2.patch | 40 ++--- ...patch => sepostgresql-policy-8.3.8-2.patch | 0 ...atch => sepostgresql-sepgsql-8.3.8-2.patch | 148 +++++++++--------- sepostgresql.init | 4 +- sepostgresql.spec | 39 ++--- sources | 2 +- 7 files changed, 111 insertions(+), 124 deletions(-) rename sepostgresql-pg_dump-8.3.7-2.patch => sepostgresql-pg_dump-8.3.8-2.patch (94%) rename sepostgresql-policy-8.3.7-2.patch => sepostgresql-policy-8.3.8-2.patch (100%) rename sepostgresql-sepgsql-8.3.7-2.patch => sepostgresql-sepgsql-8.3.8-2.patch (98%) diff --git a/.cvsignore b/.cvsignore index e18d446..28f3a6b 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -postgresql-8.3.7.tar.bz2 +postgresql-8.3.8.tar.bz2 diff --git a/sepostgresql-pg_dump-8.3.7-2.patch b/sepostgresql-pg_dump-8.3.8-2.patch similarity index 94% rename from sepostgresql-pg_dump-8.3.7-2.patch rename to sepostgresql-pg_dump-8.3.8-2.patch index adea1a2..051b769 100644 --- a/sepostgresql-pg_dump-8.3.7-2.patch +++ b/sepostgresql-pg_dump-8.3.8-2.patch @@ -1,6 +1,6 @@ diff -rpNU3 base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c ---- base/src/bin/initdb/initdb.c 2008-11-05 09:57:00.000000000 +0900 -+++ sepgsql/src/bin/initdb/initdb.c 2008-12-28 01:19:14.000000000 +0900 +--- base/src/bin/initdb/initdb.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/bin/initdb/initdb.c 2009-09-10 20:54:22.000000000 +0900 @@ -94,6 +94,7 @@ static bool debug = false; static bool noclean = false; static bool show_setting = false; @@ -9,7 +9,7 @@ diff -rpNU3 base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c /* internal vars */ -@@ -1212,6 +1213,11 @@ setup_config(void) +@@ -1224,6 +1225,11 @@ setup_config(void) "#default_text_search_config = 'pg_catalog.simple'", repltok); @@ -21,7 +21,7 @@ diff -rpNU3 base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); writefile(path, conflines); -@@ -2383,6 +2389,7 @@ usage(const char *progname) +@@ -2395,6 +2401,7 @@ usage(const char *progname) printf(_(" -U, --username=NAME database superuser name\n")); printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); printf(_(" --pwfile=FILE read password for the new superuser from file\n")); @@ -29,7 +29,7 @@ diff -rpNU3 base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c printf(_(" -?, --help show this help, then exit\n")); printf(_(" -V, --version output version information, then exit\n")); printf(_("\nLess commonly used options:\n")); -@@ -2417,6 +2424,7 @@ main(int argc, char *argv[]) +@@ -2429,6 +2436,7 @@ main(int argc, char *argv[]) {"auth", required_argument, NULL, 'A'}, {"pwprompt", no_argument, NULL, 'W'}, {"pwfile", required_argument, NULL, 9}, @@ -37,7 +37,7 @@ diff -rpNU3 base/src/bin/initdb/initdb.c sepgsql/src/bin/initdb/initdb.c {"username", required_argument, NULL, 'U'}, {"help", no_argument, NULL, '?'}, {"version", no_argument, NULL, 'V'}, -@@ -2531,6 +2539,9 @@ main(int argc, char *argv[]) +@@ -2543,6 +2551,9 @@ main(int argc, char *argv[]) case 9: pwfilename = xstrdup(optarg); break; @@ -336,8 +336,8 @@ diff -rpNU3 base/src/bin/pg_dump/pg_ace_dump.h sepgsql/src/bin/pg_dump/pg_ace_du + +#endif diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c ---- base/src/bin/pg_dump/pg_dump.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/src/bin/pg_dump/pg_dump.c 2009-02-02 11:58:34.000000000 +0900 +--- base/src/bin/pg_dump/pg_dump.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/bin/pg_dump/pg_dump.c 2009-09-10 20:54:22.000000000 +0900 @@ -50,6 +50,7 @@ int optreset; #include "pg_backup_archiver.h" @@ -399,7 +399,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c fmtQualifiedId(tbinfo->dobj.namespace->dobj.name, classname)); } -@@ -1785,11 +1795,14 @@ dumpBlobComments(Archive *AH, void *arg) +@@ -1791,11 +1801,14 @@ dumpBlobComments(Archive *AH, void *arg) Oid blobOid; char *comment; @@ -415,7 +415,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c comment = PQgetvalue(res, i, 1); printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ", -@@ -2927,6 +2940,7 @@ getTables(int *numTables) +@@ -2933,6 +2946,7 @@ getTables(int *numTables) "d.refobjsubid as owning_col, " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " "array_to_string(c.reloptions, ', ') as reloptions " @@ -423,7 +423,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c "from pg_class c " "left join pg_depend d on " "(c.relkind = '%c' and " -@@ -2936,6 +2950,7 @@ getTables(int *numTables) +@@ -2942,6 +2956,7 @@ getTables(int *numTables) "where relkind in ('%c', '%c', '%c', '%c') " "order by c.oid", username_subquery, @@ -431,7 +431,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c RELKIND_SEQUENCE, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); -@@ -3132,6 +3147,7 @@ getTables(int *numTables) +@@ -3138,6 +3153,7 @@ getTables(int *numTables) } tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace)); tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions)); @@ -439,7 +439,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c /* other fields were zeroed above */ -@@ -4363,11 +4379,13 @@ getTableAttrs(TableInfo *tblinfo, int nu +@@ -4369,11 +4385,13 @@ getTableAttrs(TableInfo *tblinfo, int nu appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, " "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, " "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname " @@ -453,7 +453,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c tbinfo->dobj.catId.oid); } else if (g_fout->remoteVersion >= 70100) -@@ -4426,6 +4444,7 @@ getTableAttrs(TableInfo *tblinfo, int nu +@@ -4432,6 +4450,7 @@ getTableAttrs(TableInfo *tblinfo, int nu tbinfo->typstorage = (char *) malloc(ntups * sizeof(char)); tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool)); tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool)); @@ -461,7 +461,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool)); tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *)); tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); -@@ -4457,6 +4476,8 @@ getTableAttrs(TableInfo *tblinfo, int nu +@@ -4463,6 +4482,8 @@ getTableAttrs(TableInfo *tblinfo, int nu tbinfo->inhAttrs[j] = false; tbinfo->inhAttrDef[j] = false; tbinfo->inhNotNull[j] = false; @@ -470,7 +470,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c } PQclear(res); -@@ -6460,8 +6481,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo) +@@ -6466,8 +6487,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "provolatile, proisstrict, prosecdef, " "proconfig, procost, prorows, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname " @@ -481,7 +481,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c finfo->dobj.catId.oid); } else if (g_fout->remoteVersion >= 80100) -@@ -6699,6 +6722,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) +@@ -6705,6 +6728,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) if (prosecdef[0] == 't') appendPQExpBuffer(q, " SECURITY DEFINER"); @@ -490,7 +490,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c /* * COST and ROWS are emitted only if present and not default, so as not to * break backwards-compatibility of the dump without need. Keep this code -@@ -8780,6 +8805,8 @@ dumpTableSchema(Archive *fout, TableInfo +@@ -8786,6 +8811,8 @@ dumpTableSchema(Archive *fout, TableInfo if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j]) appendPQExpBuffer(q, " NOT NULL"); @@ -499,7 +499,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c actual_atts++; } } -@@ -8827,6 +8854,8 @@ dumpTableSchema(Archive *fout, TableInfo +@@ -8833,6 +8860,8 @@ dumpTableSchema(Archive *fout, TableInfo if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions); @@ -508,7 +508,7 @@ diff -rpNU3 base/src/bin/pg_dump/pg_dump.c sepgsql/src/bin/pg_dump/pg_dump.c appendPQExpBuffer(q, ";\n"); /* Loop dumping statistics and storage statements */ -@@ -10244,6 +10273,10 @@ fmtCopyColumnList(const TableInfo *ti) +@@ -10250,6 +10279,10 @@ fmtCopyColumnList(const TableInfo *ti) appendPQExpBuffer(q, "("); needComma = false; diff --git a/sepostgresql-policy-8.3.7-2.patch b/sepostgresql-policy-8.3.8-2.patch similarity index 100% rename from sepostgresql-policy-8.3.7-2.patch rename to sepostgresql-policy-8.3.8-2.patch diff --git a/sepostgresql-sepgsql-8.3.7-2.patch b/sepostgresql-sepgsql-8.3.8-2.patch similarity index 98% rename from sepostgresql-sepgsql-8.3.7-2.patch rename to sepostgresql-sepgsql-8.3.8-2.patch index ef2c562..98f4e86 100644 --- a/sepostgresql-sepgsql-8.3.7-2.patch +++ b/sepostgresql-sepgsql-8.3.8-2.patch @@ -1,6 +1,6 @@ diff -rpNU3 base/configure sepgsql/configure ---- base/configure 2009-03-15 17:47:25.000000000 +0900 -+++ sepgsql/configure 2009-03-15 17:53:20.000000000 +0900 +--- base/configure 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/configure 2009-09-10 20:54:22.000000000 +0900 @@ -314,7 +314,7 @@ ac_includes_default="\ # include #endif" @@ -143,8 +143,8 @@ diff -rpNU3 base/configure sepgsql/configure s,@ELF_SYS@,$ELF_SYS,;t t s,@LDFLAGS_SL@,$LDFLAGS_SL,;t t diff -rpNU3 base/configure.in sepgsql/configure.in ---- base/configure.in 2009-03-15 17:47:25.000000000 +0900 -+++ sepgsql/configure.in 2009-03-15 17:53:20.000000000 +0900 +--- base/configure.in 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/configure.in 2009-09-10 20:54:22.000000000 +0900 @@ -626,6 +626,19 @@ PGAC_ARG_BOOL(with, zlib, yes, AC_SUBST(with_zlib) @@ -984,8 +984,8 @@ diff -rpNU3 base/src/backend/Makefile sepgsql/src/backend/Makefile all: submake-libpgport postgres $(POSTGRES_IMP) diff -rpNU3 base/src/backend/access/common/heaptuple.c sepgsql/src/backend/access/common/heaptuple.c ---- base/src/backend/access/common/heaptuple.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/access/common/heaptuple.c 2008-12-28 01:06:59.000000000 +0900 +--- base/src/backend/access/common/heaptuple.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/access/common/heaptuple.c 2009-09-10 20:54:22.000000000 +0900 @@ -67,6 +67,7 @@ #include "access/heapam.h" #include "access/tuptoaster.h" @@ -1164,8 +1164,8 @@ diff -rpNU3 base/src/backend/access/common/tupdesc.c sepgsql/src/backend/access/ for (i = 0; i < tupdesc1->natts; i++) { diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/heap/heapam.c ---- base/src/backend/access/heap/heapam.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/src/backend/access/heap/heapam.c 2009-02-02 11:58:34.000000000 +0900 +--- base/src/backend/access/heap/heapam.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/access/heap/heapam.c 2009-09-10 20:54:22.000000000 +0900 @@ -50,6 +50,7 @@ #include "catalog/namespace.h" #include "miscadmin.h" @@ -1174,7 +1174,7 @@ diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/hea #include "storage/procarray.h" #include "storage/smgr.h" #include "utils/datum.h" -@@ -1949,6 +1950,12 @@ heap_insert(Relation relation, HeapTuple +@@ -1958,6 +1959,12 @@ heap_insert(Relation relation, HeapTuple Oid simple_heap_insert(Relation relation, HeapTuple tup) { @@ -1187,7 +1187,7 @@ diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/hea return heap_insert(relation, tup, GetCurrentCommandId(true), true, true); } -@@ -2230,6 +2237,12 @@ simple_heap_delete(Relation relation, It +@@ -2239,6 +2246,12 @@ simple_heap_delete(Relation relation, It ItemPointerData update_ctid; TransactionId update_xmax; @@ -1200,7 +1200,7 @@ diff -rpNU3 base/src/backend/access/heap/heapam.c sepgsql/src/backend/access/hea result = heap_delete(relation, tid, &update_ctid, &update_xmax, GetCurrentCommandId(true), InvalidSnapshot, -@@ -2874,6 +2887,12 @@ simple_heap_update(Relation relation, It +@@ -2883,6 +2896,12 @@ simple_heap_update(Relation relation, It ItemPointerData update_ctid; TransactionId update_xmax; @@ -2874,8 +2874,8 @@ diff -rpNU3 base/src/backend/executor/execScan.c sepgsql/src/backend/executor/ex return true; } diff -rpNU3 base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/execTuples.c ---- base/src/backend/executor/execTuples.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/executor/execTuples.c 2008-12-28 01:06:59.000000000 +0900 +--- base/src/backend/executor/execTuples.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/executor/execTuples.c 2009-09-10 20:54:22.000000000 +0900 @@ -100,7 +100,7 @@ @@ -2885,7 +2885,7 @@ diff -rpNU3 base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/ /* ---------------------------------------------------------------- -@@ -921,9 +921,9 @@ ExecInitNullTupleSlot(EState *estate, Tu +@@ -941,9 +941,9 @@ ExecInitNullTupleSlot(EState *estate, Tu * ---------------------------------------------------------------- */ TupleDesc @@ -2897,7 +2897,7 @@ diff -rpNU3 base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/ } /* ---------------------------------------------------------------- -@@ -933,13 +933,14 @@ ExecTypeFromTL(List *targetList, bool ha +@@ -953,13 +953,14 @@ ExecTypeFromTL(List *targetList, bool ha * ---------------------------------------------------------------- */ TupleDesc @@ -2915,7 +2915,7 @@ diff -rpNU3 base/src/backend/executor/execTuples.c sepgsql/src/backend/executor/ { TupleDesc typeInfo; ListCell *l; -@@ -951,6 +952,7 @@ ExecTypeFromTLInternal(List *targetList, +@@ -971,6 +972,7 @@ ExecTypeFromTLInternal(List *targetList, else len = ExecTargetListLength(targetList); typeInfo = CreateTemplateTupleDesc(len, hasoid); @@ -3111,8 +3111,8 @@ diff -rpNU3 base/src/backend/libpq/be-fsstubs.c sepgsql/src/backend/libpq/be-fss PG_RETURN_INT32(0); diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfuncs.c ---- base/src/backend/nodes/copyfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/nodes/copyfuncs.c 2009-02-17 13:32:34.000000000 +0900 +--- base/src/backend/nodes/copyfuncs.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/nodes/copyfuncs.c 2009-09-10 20:54:22.000000000 +0900 @@ -24,6 +24,7 @@ #include "nodes/plannodes.h" @@ -3137,7 +3137,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun } /* -@@ -1523,6 +1526,7 @@ _copyRangeTblEntry(RangeTblEntry *from) +@@ -1524,6 +1527,7 @@ _copyRangeTblEntry(RangeTblEntry *from) COPY_SCALAR_FIELD(inFromCl); COPY_SCALAR_FIELD(requiredPerms); COPY_SCALAR_FIELD(checkAsUser); @@ -3145,7 +3145,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun return newnode; } -@@ -1789,6 +1793,7 @@ _copyColumnDef(ColumnDef *from) +@@ -1790,6 +1794,7 @@ _copyColumnDef(ColumnDef *from) COPY_NODE_FIELD(raw_default); COPY_STRING_FIELD(cooked_default); COPY_NODE_FIELD(constraints); @@ -3153,7 +3153,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun return newnode; } -@@ -1869,6 +1874,7 @@ _copyQuery(Query *from) +@@ -1870,6 +1875,7 @@ _copyQuery(Query *from) COPY_NODE_FIELD(limitCount); COPY_NODE_FIELD(rowMarks); COPY_NODE_FIELD(setOperations); @@ -3161,7 +3161,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun return newnode; } -@@ -2105,6 +2111,7 @@ _copyCreateStmt(CreateStmt *from) +@@ -2106,6 +2112,7 @@ _copyCreateStmt(CreateStmt *from) COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(oncommit); COPY_STRING_FIELD(tablespacename); @@ -3169,7 +3169,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun return newnode; } -@@ -2998,6 +3005,25 @@ _copyValue(Value *from) +@@ -2999,6 +3006,25 @@ _copyValue(Value *from) return newnode; } @@ -3195,7 +3195,7 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun /* * copyObject * -@@ -3600,6 +3626,9 @@ copyObject(void *from) +@@ -3601,6 +3627,9 @@ copyObject(void *from) case T_XmlSerialize: retval = _copyXmlSerialize(from); break; @@ -3206,8 +3206,8 @@ diff -rpNU3 base/src/backend/nodes/copyfuncs.c sepgsql/src/backend/nodes/copyfun default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from)); diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalfuncs.c ---- base/src/backend/nodes/equalfuncs.c 2008-03-19 09:48:23.000000000 +0900 -+++ sepgsql/src/backend/nodes/equalfuncs.c 2009-01-21 17:02:57.000000000 +0900 +--- base/src/backend/nodes/equalfuncs.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/nodes/equalfuncs.c 2009-09-10 20:54:22.000000000 +0900 @@ -26,6 +26,7 @@ #include "postgres.h" @@ -3216,7 +3216,7 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf #include "utils/datum.h" -@@ -768,6 +769,7 @@ _equalQuery(Query *a, Query *b) +@@ -769,6 +770,7 @@ _equalQuery(Query *a, Query *b) COMPARE_NODE_FIELD(limitCount); COMPARE_NODE_FIELD(rowMarks); COMPARE_NODE_FIELD(setOperations); @@ -3224,7 +3224,7 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf return true; } -@@ -970,6 +972,7 @@ _equalCreateStmt(CreateStmt *a, CreateSt +@@ -971,6 +973,7 @@ _equalCreateStmt(CreateStmt *a, CreateSt COMPARE_NODE_FIELD(options); COMPARE_SCALAR_FIELD(oncommit); COMPARE_STRING_FIELD(tablespacename); @@ -3232,7 +3232,7 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf return true; } -@@ -1818,6 +1821,7 @@ _equalColumnDef(ColumnDef *a, ColumnDef +@@ -1819,6 +1822,7 @@ _equalColumnDef(ColumnDef *a, ColumnDef COMPARE_NODE_FIELD(raw_default); COMPARE_STRING_FIELD(cooked_default); COMPARE_NODE_FIELD(constraints); @@ -3240,7 +3240,7 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf return true; } -@@ -1925,6 +1929,21 @@ _equalXmlSerialize(XmlSerialize *a, XmlS +@@ -1926,6 +1930,21 @@ _equalXmlSerialize(XmlSerialize *a, XmlS } /* @@ -3262,7 +3262,7 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf * Stuff from pg_list.h */ -@@ -2527,6 +2546,9 @@ equal(void *a, void *b) +@@ -2528,6 +2547,9 @@ equal(void *a, void *b) case T_XmlSerialize: retval = _equalXmlSerialize(a, b); break; @@ -3273,8 +3273,8 @@ diff -rpNU3 base/src/backend/nodes/equalfuncs.c sepgsql/src/backend/nodes/equalf default: elog(ERROR, "unrecognized node type: %d", diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs.c ---- base/src/backend/nodes/outfuncs.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/src/backend/nodes/outfuncs.c 2009-02-02 11:58:34.000000000 +0900 +--- base/src/backend/nodes/outfuncs.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/nodes/outfuncs.c 2009-09-10 20:54:22.000000000 +0900 @@ -26,6 +26,7 @@ #include "lib/stringinfo.h" #include "nodes/plannodes.h" @@ -3307,7 +3307,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1545,6 +1549,7 @@ _outCreateStmt(StringInfo str, CreateStm +@@ -1546,6 +1550,7 @@ _outCreateStmt(StringInfo str, CreateStm WRITE_NODE_FIELD(options); WRITE_ENUM_FIELD(oncommit, OnCommitAction); WRITE_STRING_FIELD(tablespacename); @@ -3315,7 +3315,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1660,6 +1665,7 @@ _outColumnDef(StringInfo str, ColumnDef +@@ -1661,6 +1666,7 @@ _outColumnDef(StringInfo str, ColumnDef WRITE_NODE_FIELD(raw_default); WRITE_STRING_FIELD(cooked_default); WRITE_NODE_FIELD(constraints); @@ -3323,7 +3323,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1749,6 +1755,7 @@ _outQuery(StringInfo str, Query *node) +@@ -1750,6 +1756,7 @@ _outQuery(StringInfo str, Query *node) WRITE_NODE_FIELD(limitCount); WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(setOperations); @@ -3331,7 +3331,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -1834,6 +1841,7 @@ _outRangeTblEntry(StringInfo str, RangeT +@@ -1835,6 +1842,7 @@ _outRangeTblEntry(StringInfo str, RangeT WRITE_BOOL_FIELD(inFromCl); WRITE_UINT_FIELD(requiredPerms); WRITE_OID_FIELD(checkAsUser); @@ -3339,7 +3339,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs } static void -@@ -2046,6 +2054,29 @@ _outFkConstraint(StringInfo str, FkConst +@@ -2047,6 +2055,29 @@ _outFkConstraint(StringInfo str, FkConst WRITE_BOOL_FIELD(skip_validation); } @@ -3369,7 +3369,7 @@ diff -rpNU3 base/src/backend/nodes/outfuncs.c sepgsql/src/backend/nodes/outfuncs /* * _outNode - -@@ -2439,6 +2470,9 @@ _outNode(StringInfo str, void *obj) +@@ -2440,6 +2471,9 @@ _outNode(StringInfo str, void *obj) case T_XmlSerialize: _outXmlSerialize(str, obj); break; @@ -3458,8 +3458,8 @@ diff -rpNU3 base/src/backend/nodes/readfuncs.c sepgsql/src/backend/nodes/readfun { elog(ERROR, "badly formatted node string \"%.32s\"...", token); diff -rpNU3 base/src/backend/optimizer/plan/createplan.c sepgsql/src/backend/optimizer/plan/createplan.c ---- base/src/backend/optimizer/plan/createplan.c 2008-06-12 22:34:19.000000000 +0900 -+++ sepgsql/src/backend/optimizer/plan/createplan.c 2008-06-14 02:36:58.000000000 +0900 +--- base/src/backend/optimizer/plan/createplan.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/optimizer/plan/createplan.c 2009-09-10 20:54:22.000000000 +0900 @@ -287,6 +287,12 @@ create_scan_plan(PlannerInfo *root, Path } @@ -3880,8 +3880,8 @@ diff -rpNU3 base/src/backend/parser/parse_target.c sepgsql/src/backend/parser/pa /* * Check for duplicates, but only of whole columns --- we allow diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmaster/postmaster.c ---- base/src/backend/postmaster/postmaster.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/postmaster/postmaster.c 2008-09-25 15:22:04.000000000 +0900 +--- base/src/backend/postmaster/postmaster.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/postmaster/postmaster.c 2009-09-10 20:54:22.000000000 +0900 @@ -107,6 +107,7 @@ #include "postmaster/pgarch.h" #include "postmaster/postmaster.h" @@ -3900,7 +3900,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas /* Startup/shutdown state */ #define NoShutdown 0 -@@ -1321,6 +1323,10 @@ ServerLoop(void) +@@ -1323,6 +1325,10 @@ ServerLoop(void) if (PgStatPID == 0 && pmState == PM_RUN) PgStatPID = pgstat_start(); @@ -3908,10 +3908,10 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas + 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 -@@ -1911,6 +1917,8 @@ SIGHUP_handler(SIGNAL_ARGS) + /* If we need to signal the autovacuum launcher, do so now */ + if (avlauncher_needs_signal) + { +@@ -1921,6 +1927,8 @@ SIGHUP_handler(SIGNAL_ARGS) signal_child(PgArchPID, SIGHUP); if (SysLoggerPID != 0) signal_child(SysLoggerPID, SIGHUP); @@ -3920,7 +3920,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas /* PgStatPID does not currently need SIGHUP */ /* Reload authentication config files too */ -@@ -1968,6 +1976,9 @@ pmdie(SIGNAL_ARGS) +@@ -1978,6 +1986,9 @@ pmdie(SIGNAL_ARGS) /* and the walwriter too */ if (WalWriterPID != 0) signal_child(WalWriterPID, SIGTERM); @@ -3930,7 +3930,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas pmState = PM_WAIT_BACKENDS; } -@@ -2006,6 +2017,9 @@ pmdie(SIGNAL_ARGS) +@@ -2017,6 +2028,9 @@ pmdie(SIGNAL_ARGS) /* and the walwriter too */ if (WalWriterPID != 0) signal_child(WalWriterPID, SIGTERM); @@ -3940,7 +3940,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas pmState = PM_WAIT_BACKENDS; } -@@ -2039,6 +2053,8 @@ pmdie(SIGNAL_ARGS) +@@ -2050,6 +2064,8 @@ pmdie(SIGNAL_ARGS) signal_child(PgArchPID, SIGQUIT); if (PgStatPID != 0) signal_child(PgStatPID, SIGQUIT); @@ -3949,7 +3949,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas ExitPostmaster(0); break; } -@@ -2287,6 +2303,16 @@ reaper(SIGNAL_ARGS) +@@ -2298,6 +2314,16 @@ reaper(SIGNAL_ARGS) continue; } @@ -3966,7 +3966,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas /* * Else do standard backend child cleanup. */ -@@ -2454,6 +2480,18 @@ HandleChildCrash(int pid, int exitstatus +@@ -2465,6 +2491,18 @@ HandleChildCrash(int pid, int exitstatus signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); } @@ -3985,7 +3985,7 @@ diff -rpNU3 base/src/backend/postmaster/postmaster.c sepgsql/src/backend/postmas /* * 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 -@@ -2573,7 +2611,8 @@ PostmasterStateMachine(void) +@@ -2584,7 +2622,8 @@ PostmasterStateMachine(void) StartupPID == 0 && (BgWriterPID == 0 || !FatalError) && WalWriterPID == 0 && @@ -11276,9 +11276,9 @@ diff -rpNU3 base/src/backend/utils/cache/catcache.c sepgsql/src/backend/utils/ca /* * SearchCatCacheList diff -rpNU3 base/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/cache/plancache.c ---- base/src/backend/utils/cache/plancache.c 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/src/backend/utils/cache/plancache.c 2009-02-02 11:58:34.000000000 +0900 -@@ -880,12 +880,14 @@ PlanCacheComputeResultDesc(List *stmt_li +--- base/src/backend/utils/cache/plancache.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/utils/cache/plancache.c 2009-09-10 20:54:22.000000000 +0900 +@@ -894,12 +894,14 @@ PlanCacheComputeResultDesc(List *stmt_li if (IsA(node, Query)) { query = (Query *) node; @@ -11295,7 +11295,7 @@ diff -rpNU3 base/src/backend/utils/cache/plancache.c sepgsql/src/backend/utils/c } /* other cases shouldn't happen, but return NULL */ break; -@@ -896,13 +898,15 @@ PlanCacheComputeResultDesc(List *stmt_li +@@ -910,13 +912,15 @@ PlanCacheComputeResultDesc(List *stmt_li { query = (Query *) node; Assert(query->returningList); @@ -11457,8 +11457,8 @@ diff -rpNU3 base/src/backend/utils/cache/syscache.c sepgsql/src/backend/utils/ca * * A convenience routine that does SearchSysCache and (if successful) diff -rpNU3 base/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/dfmgr.c ---- base/src/backend/utils/fmgr/dfmgr.c 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/backend/utils/fmgr/dfmgr.c 2008-06-26 10:27:05.000000000 +0900 +--- base/src/backend/utils/fmgr/dfmgr.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/utils/fmgr/dfmgr.c 2009-09-10 20:54:22.000000000 +0900 @@ -22,6 +22,7 @@ #include "port/dynloader/win32.h" #endif @@ -11495,7 +11495,7 @@ diff -rpNU3 base/src/backend/utils/fmgr/dfmgr.c sepgsql/src/backend/utils/fmgr/d /* Unload the library if currently loaded */ internal_unload_library(fullname); -@@ -395,7 +401,7 @@ file_exists(const char *name) +@@ -403,7 +409,7 @@ file_exists(const char *name) * * The result will always be freshly palloc'd. */ @@ -11526,8 +11526,8 @@ diff -rpNU3 base/src/backend/utils/init/postinit.c sepgsql/src/backend/utils/ini if (!bootstrap) CommitTransactionCommand(); diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc.c ---- base/src/backend/utils/misc/guc.c 2008-09-25 15:09:40.000000000 +0900 -+++ sepgsql/src/backend/utils/misc/guc.c 2008-12-28 01:06:59.000000000 +0900 +--- base/src/backend/utils/misc/guc.c 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/backend/utils/misc/guc.c 2009-09-10 20:54:22.000000000 +0900 @@ -54,6 +54,7 @@ #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" @@ -11580,7 +11580,7 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc for (i = 0; i < num_guc_variables; i++) { struct config_generic *gconf = guc_variables[i]; -@@ -4972,6 +4994,7 @@ ExecSetVariableStmt(VariableSetStmt *stm +@@ -5002,6 +5024,7 @@ ExecSetVariableStmt(VariableSetStmt *stm { case VAR_SET_VALUE: case VAR_SET_CURRENT: @@ -11588,7 +11588,7 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc set_config_option(stmt->name, ExtractSetVariableArgs(stmt), (superuser() ? PGC_SUSET : PGC_USERSET), -@@ -5029,6 +5052,7 @@ ExecSetVariableStmt(VariableSetStmt *stm +@@ -5059,6 +5082,7 @@ ExecSetVariableStmt(VariableSetStmt *stm break; case VAR_SET_DEFAULT: case VAR_RESET: @@ -11596,7 +11596,7 @@ diff -rpNU3 base/src/backend/utils/misc/guc.c sepgsql/src/backend/utils/misc/guc set_config_option(stmt->name, NULL, (superuser() ? PGC_SUSET : PGC_USERSET), -@@ -5357,6 +5381,9 @@ EmitWarningsOnPlaceholders(const char *c +@@ -5387,6 +5411,9 @@ EmitWarningsOnPlaceholders(const char *c void GetPGVariable(const char *name, DestReceiver *dest) { @@ -11908,18 +11908,18 @@ diff -rpNU3 base/src/include/executor/executor.h sepgsql/src/include/executor/ex extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); diff -rpNU3 base/src/include/executor/tuptable.h sepgsql/src/include/executor/tuptable.h ---- base/src/include/executor/tuptable.h 2008-01-07 23:51:33.000000000 +0900 -+++ sepgsql/src/include/executor/tuptable.h 2008-12-28 01:06:59.000000000 +0900 -@@ -118,6 +118,9 @@ typedef struct TupleTableSlot - MinimalTuple tts_mintuple; /* set if it's a minimal tuple, else NULL */ - HeapTupleData tts_minhdr; /* workspace if it's a minimal tuple */ +--- base/src/include/executor/tuptable.h 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/include/executor/tuptable.h 2009-09-10 20:54:22.000000000 +0900 +@@ -127,6 +127,9 @@ typedef struct TupleTableSlot + MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */ + HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */ long tts_off; /* saved state for slot_deform_tuple */ + + /* temporary storage variables for writable system column */ + Datum tts_seclabel; /* for security label */ } TupleTableSlot; - /* + #define TTS_HAS_PHYSICAL_TUPLE(slot) \ diff -rpNU3 base/src/include/fmgr.h sepgsql/src/include/fmgr.h --- base/src/include/fmgr.h 2008-01-07 23:51:33.000000000 +0900 +++ sepgsql/src/include/fmgr.h 2009-01-16 17:07:29.000000000 +0900 @@ -12048,8 +12048,8 @@ diff -rpNU3 base/src/include/nodes/plannodes.h sepgsql/src/include/nodes/plannod /* ---------------- diff -rpNU3 base/src/include/nodes/relation.h sepgsql/src/include/nodes/relation.h ---- base/src/include/nodes/relation.h 2009-02-02 11:47:17.000000000 +0900 -+++ sepgsql/src/include/nodes/relation.h 2009-02-02 11:58:34.000000000 +0900 +--- base/src/include/nodes/relation.h 2009-09-10 20:11:35.000000000 +0900 ++++ sepgsql/src/include/nodes/relation.h 2009-09-10 20:54:22.000000000 +0900 @@ -366,6 +366,8 @@ typedef struct RelOptInfo * list just to avoid recomputing the best inner indexscan repeatedly for * similar outer relations. See comments for InnerIndexscanInfo. diff --git a/sepostgresql.init b/sepostgresql.init index e09d4aa..f72a6dc 100644 --- a/sepostgresql.init +++ b/sepostgresql.init @@ -7,9 +7,9 @@ # pidfile: /var/run/postmaster.pid #--------------------------------------------------------------------- -PGVERSION="8.3.7" +PGVERSION="8.3.8" PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9a-z]*\).*$/\1/'` -SEPGVERSION="2.1770" +SEPGVERSION="2.2300" # source function library . /etc/rc.d/init.d/functions diff --git a/sepostgresql.spec b/sepostgresql.spec index 94493fa..0831cbe 100644 --- a/sepostgresql.spec +++ b/sepostgresql.spec @@ -7,22 +7,14 @@ # SE-PostgreSQL status extension %define selinux_policy_stores targeted mls -# Check required policy version -%define fedora9 %(rpm -E '%{dist}' | grep -cE '^\.fc[1-9]$') -%if %{fedora9} -%define required_policy_version 3.3.1 -%else -%define required_policy_version 3.4.2 -%endif - %{!?ssl:%define ssl 1} Summary: Security Enhanced PostgreSQL Name: sepostgresql -Version: 8.3.7 -Release: 2.1770%{?sepgsql_extension}%{?dist} +Version: 8.3.8 +Release: 2.2300%{?sepgsql_extension}%{?dist} License: BSD Group: Applications/Databases Url: http://code.google.com/p/sepgsql/ @@ -31,16 +23,13 @@ Source0: ftp://ftp.postgresql.org/pub/source/v%{version}/postgresql-%{version}.t Source1: sepostgresql.init Source2: sepostgresql.8 Source3: sepostgresql.logrotate -Patch0: sepostgresql-sepgsql-8.3.7-2.patch -Patch1: sepostgresql-policy-8.3.7-2.patch -Patch2: sepostgresql-pg_dump-8.3.7-2.patch +Patch0: sepostgresql-sepgsql-8.3.8-2.patch +Patch1: sepostgresql-policy-8.3.8-2.patch +Patch2: sepostgresql-pg_dump-8.3.8-2.patch Patch3: sepostgresql-fedora-prefix.patch BuildRequires: perl glibc-devel bison flex readline-devel zlib-devel >= 1.0.4 BuildRequires: checkpolicy libselinux-devel >= 2.0.43 -BuildRequires: selinux-policy >= %{required_policy_version} -%if %{fedora9} -BuildRequires: selinux-policy-devel -%endif +BuildRequires: selinux-policy >= 3.4.2 %if %{ssl} BuildRequires: openssl-devel %endif @@ -50,7 +39,7 @@ Requires(preun): /sbin/chkconfig /sbin/service Requires(postun): policycoreutils Requires: postgresql-server = %{version} Requires: policycoreutils >= 2.0.16 libselinux >= 2.0.43 -Requires: selinux-policy >= %{required_policy_version} +Requires: selinux-policy >= 3.4.2 Requires: tzdata logrotate %description @@ -88,24 +77,20 @@ CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS # parallel build, if possible make %{?_smp_mflags} -%if !%{fedora9} touch src/backend/security/sepgsql/policy/sepostgresql-devel.fc make -C src/backend/security/sepgsql/policy -%endif %install rm -rf %{buildroot} make DESTDIR=%{buildroot} install -%if !%{fedora9} for store in %{selinux_policy_stores} do install -d %{buildroot}%{_datadir}/selinux/${store} install -p -m 644 src/backend/security/sepgsql/policy/sepostgresql-devel.pp.${store} \ %{buildroot}%{_datadir}/selinux/${store}/sepostgresql-devel.pp done -%endif # avoid to conflict with native postgresql package mv %{buildroot}%{_bindir} %{buildroot}%{_bindir}.orig @@ -155,7 +140,6 @@ exit 0 /sbin/chkconfig --add %{name} /sbin/ldconfig -%if !%{fedora9} for store in %{selinux_policy_stores} do # clean up legacy policy module (now it is unnecessary) @@ -165,7 +149,6 @@ do -i %{_datadir}/selinux/${store}/sepostgresql-devel.pp >& /dev/null || : fi done -%endif # Fix up non-standard file contexts /sbin/fixfiles -R %{name} restore || : @@ -214,14 +197,18 @@ fi %{_datadir}/sepgsql/conversion_create.sql %{_datadir}/sepgsql/information_schema.sql %{_datadir}/sepgsql/sql_features.txt -%if !%{fedora9} %attr(644,root,root) %{_datadir}/selinux/*/sepostgresql-devel.pp -%endif %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/data %attr(700,sepgsql,sepgsql) %dir %{_localstatedir}/lib/sepgsql/backups %changelog +* Thu Sep 10 2009 KaiGai Kohei - 8.3.8-2300 +- upgrade base PostgreSQL v8.3.7->8.3.8 + +* Fri Apr 17 2009 KaiGai Kohei - 8.3.7-1772 +- bugfix: /etc/init.d/sepostgresql initdb didn't work correctly + * Fri Mar 27 2009 KaiGai Kohei - 8.3.7-2.1770 - upgrade base PostgreSQL version 8.3.6->8.3.7 diff --git a/sources b/sources index 7a88da9..76ef09b 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -7b7e91a2221e55fe1b167e663217a96d postgresql-8.3.7.tar.bz2 +aac683d03f765dc58a3a0e5eaa1927bf postgresql-8.3.8.tar.bz2 From d46b4f78239f55e1ac68da07bdf6f16ad563e8fb Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Thu, 26 Nov 2009 01:38:42 +0000 Subject: [PATCH 6/7] Fix typo that causes a failure to update the common directory. (releng #2781) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dad7c56..59ecad3 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ NAME := sepostgresql SPECFILE = $(firstword $(wildcard *.spec)) define find-makefile-common -for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done +for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$d/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done endef MAKEFILE_COMMON := $(shell $(find-makefile-common)) From 8a1b36445daa0ad3d7df360f369c5d331f53ad58 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Thu, 29 Jul 2010 12:35:37 +0000 Subject: [PATCH 7/7] dist-git conversion --- .cvsignore => .gitignore | 0 Makefile | 21 --------------------- branch | 1 - 3 files changed, 22 deletions(-) rename .cvsignore => .gitignore (100%) delete mode 100644 Makefile delete mode 100644 branch diff --git a/.cvsignore b/.gitignore similarity index 100% rename from .cvsignore rename to .gitignore diff --git a/Makefile b/Makefile deleted file mode 100644 index 59ecad3..0000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Makefile for source rpm: sepostgresql -# $Id$ -NAME := sepostgresql -SPECFILE = $(firstword $(wildcard *.spec)) - -define find-makefile-common -for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$d/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done -endef - -MAKEFILE_COMMON := $(shell $(find-makefile-common)) - -ifeq ($(MAKEFILE_COMMON),) -# attept a checkout -define checkout-makefile-common -test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2 -endef - -MAKEFILE_COMMON := $(shell $(checkout-makefile-common)) -endif - -include $(MAKEFILE_COMMON) diff --git a/branch b/branch deleted file mode 100644 index dc32377..0000000 --- a/branch +++ /dev/null @@ -1 +0,0 @@ -F-10