Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Functions | Variables

hooks.c File Reference

#include "postgres.h"
#include "catalog/dependency.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_class.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "commands/seclabel.h"
#include "executor/executor.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "tcop/utility.h"
#include "utils/guc.h"
#include "sepgsql.h"
Include dependency graph for hooks.c:

Go to the source code of this file.

Data Structures

struct  sepgsql_context_info_t

Functions

void _PG_init (void)
bool sepgsql_get_permissive (void)
bool sepgsql_get_debug_audit (void)
static void sepgsql_object_access (ObjectAccessType access, Oid classId, Oid objectId, int subId, void *arg)
static bool sepgsql_exec_check_perms (List *rangeTabls, bool abort)
static void sepgsql_utility_command (Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)

Variables

 PG_MODULE_MAGIC
static object_access_hook_type next_object_access_hook = NULL
static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL
static ProcessUtility_hook_type next_ProcessUtility_hook = NULL
static sepgsql_context_info_t sepgsql_context_info
static bool sepgsql_permissive
static bool sepgsql_debug_audit

Function Documentation

void _PG_init ( void   ) 

Definition at line 386 of file hooks.c.

References DefineCustomBoolVariable(), ereport, errcode(), errmsg(), ERROR, ExecutorCheckPerms_hook, GUC_NOT_IN_SAMPLE, IsUnderPostmaster, next_exec_check_perms_hook, next_object_access_hook, next_ProcessUtility_hook, NULL, object_access_hook, PGC_SIGHUP, PGC_USERSET, ProcessUtility_hook, register_label_provider(), sepgsql_avc_init(), sepgsql_debug_audit, sepgsql_init_client_label(), SEPGSQL_LABEL_TAG, SEPGSQL_MODE_DISABLED, sepgsql_object_relabel(), sepgsql_permissive, and sepgsql_set_mode().

{
    /*
     * We allow to load the SE-PostgreSQL module on single-user-mode or
     * shared_preload_libraries settings only.
     */
    if (IsUnderPostmaster)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
             errmsg("sepgsql must be loaded via shared_preload_libraries")));

    /*
     * Check availability of SELinux on the platform. If disabled, we cannot
     * activate any SE-PostgreSQL features, and we have to skip rest of
     * initialization.
     */
    if (is_selinux_enabled() < 1)
    {
        sepgsql_set_mode(SEPGSQL_MODE_DISABLED);
        return;
    }

    /*
     * sepgsql.permissive = (on|off)
     *
     * This variable controls performing mode of SE-PostgreSQL on user's
     * session.
     */
    DefineCustomBoolVariable("sepgsql.permissive",
                             "Turn on/off permissive mode in SE-PostgreSQL",
                             NULL,
                             &sepgsql_permissive,
                             false,
                             PGC_SIGHUP,
                             GUC_NOT_IN_SAMPLE,
                             NULL,
                             NULL,
                             NULL);

    /*
     * sepgsql.debug_audit = (on|off)
     *
     * This variable allows users to turn on/off audit logs on access control
     * decisions, independent from auditallow/auditdeny setting in the
     * security policy. We intend to use this option for debugging purpose.
     */
    DefineCustomBoolVariable("sepgsql.debug_audit",
                             "Turn on/off debug audit messages",
                             NULL,
                             &sepgsql_debug_audit,
                             false,
                             PGC_USERSET,
                             GUC_NOT_IN_SAMPLE,
                             NULL,
                             NULL,
                             NULL);

    /* Initialize userspace access vector cache */
    sepgsql_avc_init();

    /* Initialize security label of the client and related stuff */
    sepgsql_init_client_label();

    /* Security label provider hook */
    register_label_provider(SEPGSQL_LABEL_TAG,
                            sepgsql_object_relabel);

    /* Object access hook */
    next_object_access_hook = object_access_hook;
    object_access_hook = sepgsql_object_access;

    /* DML permission check */
    next_exec_check_perms_hook = ExecutorCheckPerms_hook;
    ExecutorCheckPerms_hook = sepgsql_exec_check_perms;

    /* ProcessUtility hook */
    next_ProcessUtility_hook = ProcessUtility_hook;
    ProcessUtility_hook = sepgsql_utility_command;

    /* init contextual info */
    memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
}

static bool sepgsql_exec_check_perms ( List rangeTabls,
bool  abort 
) [static]

Definition at line 277 of file hooks.c.

References next_exec_check_perms_hook, and sepgsql_dml_privileges().

{
    /*
     * If security provider is stacking and one of them replied 'false' at
     * least, we don't need to check any more.
     */
    if (next_exec_check_perms_hook &&
        !(*next_exec_check_perms_hook) (rangeTabls, abort))
        return false;

    if (!sepgsql_dml_privileges(rangeTabls, abort))
        return false;

    return true;
}

bool sepgsql_get_debug_audit ( void   ) 

Definition at line 75 of file hooks.c.

References sepgsql_debug_audit.

Referenced by sepgsql_avc_check_perms_label(), and sepgsql_check_perms().

{
    return sepgsql_debug_audit;
}

bool sepgsql_get_permissive ( void   ) 

Definition at line 64 of file hooks.c.

References sepgsql_permissive.

Referenced by sepgsql_client_auth().

{
    return sepgsql_permissive;
}

static void sepgsql_object_access ( ObjectAccessType  access,
Oid  classId,
Oid  objectId,
int  subId,
void *  arg 
) [static]

Definition at line 87 of file hooks.c.

References Assert, sepgsql_context_info_t::createdb_dtemplate, DatabaseRelationId, ObjectAccessDrop::dropflags, elog, ObjectAccessNamespaceSearch::ereport_on_violation, ERROR, ObjectAccessPostAlter::is_internal, ObjectAccessPostCreate::is_internal, NamespaceRelationId, next_object_access_hook, OAT_DROP, OAT_FUNCTION_EXECUTE, OAT_NAMESPACE_SEARCH, OAT_POST_ALTER, OAT_POST_CREATE, PERFORM_DELETION_INTERNAL, ProcedureRelationId, RelationRelationId, ObjectAccessNamespaceSearch::result, sepgsql_attribute_drop(), sepgsql_attribute_post_create(), sepgsql_attribute_setattr(), sepgsql_database_drop(), sepgsql_database_post_create(), sepgsql_database_setattr(), sepgsql_proc_drop(), sepgsql_proc_execute(), sepgsql_proc_post_create(), sepgsql_proc_setattr(), sepgsql_relation_drop(), sepgsql_relation_post_create(), sepgsql_relation_setattr(), sepgsql_schema_drop(), sepgsql_schema_post_create(), sepgsql_schema_search(), and sepgsql_schema_setattr().

{
    if (next_object_access_hook)
        (*next_object_access_hook) (access, classId, objectId, subId, arg);

    switch (access)
    {
        case OAT_POST_CREATE:
            {
                ObjectAccessPostCreate *pc_arg = arg;
                bool    is_internal;

                is_internal = pc_arg ? pc_arg->is_internal : false;

                switch (classId)
                {
                    case DatabaseRelationId:
                        Assert(!is_internal);
                        sepgsql_database_post_create(objectId,
                                                     sepgsql_context_info.createdb_dtemplate);
                        break;

                    case NamespaceRelationId:
                        Assert(!is_internal);
                        sepgsql_schema_post_create(objectId);
                        break;

                    case RelationRelationId:
                        if (subId == 0)
                        {
                            /*
                             * The cases in which we want to apply permission
                             * checks on creation of a new relation correspond
                             * to direct user invocation.  For internal uses,
                             * that is creation of toast tables, index rebuild
                             * or ALTER TABLE commands, we need neither
                             * assignment of security labels nor permission
                             * checks.
                             */
                            if (is_internal)
                                break;

                            sepgsql_relation_post_create(objectId);
                        }
                        else
                            sepgsql_attribute_post_create(objectId, subId);
                        break;

                    case ProcedureRelationId:
                        Assert(!is_internal);
                        sepgsql_proc_post_create(objectId);
                        break;

                    default:
                        /* Ignore unsupported object classes */
                        break;
                }
            }
            break;

        case OAT_DROP:
            {
                ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;

                /*
                 * No need to apply permission checks on object deletion due
                 * to internal cleanups; such as removal of temporary database
                 * object on session closed.
                 */
                if ((drop_arg->dropflags & PERFORM_DELETION_INTERNAL) != 0)
                    break;

                switch (classId)
                {
                    case DatabaseRelationId:
                        sepgsql_database_drop(objectId);
                        break;

                    case NamespaceRelationId:
                        sepgsql_schema_drop(objectId);
                        break;

                    case RelationRelationId:
                        if (subId == 0)
                            sepgsql_relation_drop(objectId);
                        else
                            sepgsql_attribute_drop(objectId, subId);
                        break;

                    case ProcedureRelationId:
                        sepgsql_proc_drop(objectId);
                        break;

                    default:
                        /* Ignore unsupported object classes */
                        break;
                }
            }
            break;

        case OAT_POST_ALTER:
            {
                ObjectAccessPostAlter  *pa_arg = arg;
                bool    is_internal = pa_arg->is_internal;

                switch (classId)
                {
                    case DatabaseRelationId:
                        Assert(!is_internal);
                        sepgsql_database_setattr(objectId);
                        break;

                    case NamespaceRelationId:
                        Assert(!is_internal);
                        sepgsql_schema_setattr(objectId);
                        break;

                    case RelationRelationId:
                        if (subId == 0)
                        {
                            /*
                             * A case when we don't want to apply permission
                             * check is that relation is internally altered
                             * without user's intention. E.g, no need to
                             * check on toast table/index to be renamed at
                             * end of the table rewrites.
                             */
                            if (is_internal)
                                break;

                            sepgsql_relation_setattr(objectId);
                        }
                        else
                            sepgsql_attribute_setattr(objectId, subId);
                        break;

                    case ProcedureRelationId:
                        Assert(!is_internal);
                        sepgsql_proc_setattr(objectId);
                        break;

                    default:
                        /* Ignore unsupported object classes */
                        break;
                }
            }
            break;

        case OAT_NAMESPACE_SEARCH:
            {
                ObjectAccessNamespaceSearch   *ns_arg = arg;

                /*
                 * If stacked extension already decided not to allow users
                 * to search this schema, we just stick with that decision.
                 */
                if (!ns_arg->result)
                    break;

                Assert(classId == NamespaceRelationId);
                Assert(ns_arg->result);
                ns_arg->result
                    = sepgsql_schema_search(objectId,
                                            ns_arg->ereport_on_violation);
            }
            break;

        case OAT_FUNCTION_EXECUTE:
            {
                Assert(classId == ProcedureRelationId);
                sepgsql_proc_execute(objectId);
            }
            break;

        default:
            elog(ERROR, "unexpected object access type: %d", (int) access);
            break;
    }
}

static void sepgsql_utility_command ( Node parsetree,
const char *  queryString,
ProcessUtilityContext  context,
ParamListInfo  params,
DestReceiver dest,
char *  completionTag 
) [static]

Definition at line 300 of file hooks.c.

References DefElem::arg, sepgsql_context_info_t::cmdtype, sepgsql_context_info_t::createdb_dtemplate, DefElem::defname, ereport, errcode(), errmsg(), ERROR, lfirst, next_ProcessUtility_hook, nodeTag, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, sepgsql_getenforce(), standard_ProcessUtility(), strVal, T_CreatedbStmt, and T_LoadStmt.

{
    sepgsql_context_info_t saved_context_info = sepgsql_context_info;
    ListCell   *cell;

    PG_TRY();
    {
        /*
         * Check command tag to avoid nefarious operations, and save the
         * current contextual information to determine whether we should apply
         * permission checks here, or not.
         */
        sepgsql_context_info.cmdtype = nodeTag(parsetree);

        switch (nodeTag(parsetree))
        {
            case T_CreatedbStmt:

                /*
                 * We hope to reference name of the source database, but it
                 * does not appear in system catalog. So, we save it here.
                 */
                foreach(cell, ((CreatedbStmt *) parsetree)->options)
                {
                    DefElem    *defel = (DefElem *) lfirst(cell);

                    if (strcmp(defel->defname, "template") == 0)
                    {
                        sepgsql_context_info.createdb_dtemplate
                            = strVal(defel->arg);
                        break;
                    }
                }
                break;

            case T_LoadStmt:

                /*
                 * We reject LOAD command across the board on enforcing mode,
                 * because a binary module can arbitrarily override hooks.
                 */
                if (sepgsql_getenforce())
                {
                    ereport(ERROR,
                            (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                             errmsg("SELinux: LOAD is not permitted")));
                }
                break;
            default:

                /*
                 * Right now we don't check any other utility commands,
                 * because it needs more detailed information to make access
                 * control decision here, but we don't want to have two parse
                 * and analyze routines individually.
                 */
                break;
        }

        if (next_ProcessUtility_hook)
            (*next_ProcessUtility_hook) (parsetree, queryString,
                                         context, params,
                                         dest, completionTag);
        else
            standard_ProcessUtility(parsetree, queryString,
                                    context, params,
                                    dest, completionTag);
    }
    PG_CATCH();
    {
        sepgsql_context_info = saved_context_info;
        PG_RE_THROW();
    }
    PG_END_TRY();
    sepgsql_context_info = saved_context_info;
}


Variable Documentation

Definition at line 39 of file hooks.c.

Referenced by _PG_init(), and sepgsql_exec_check_perms().

Definition at line 38 of file hooks.c.

Referenced by _PG_init(), and sepgsql_object_access().

Definition at line 40 of file hooks.c.

Referenced by _PG_init(), and sepgsql_utility_command().

Definition at line 28 of file hooks.c.

Definition at line 56 of file hooks.c.

Definition at line 72 of file hooks.c.

Referenced by _PG_init(), and sepgsql_get_debug_audit().

Definition at line 61 of file hooks.c.

Referenced by _PG_init(), and sepgsql_get_permissive().