Header And Logo

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

Data Structures | Functions | Variables

label.c File Reference

#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/genam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_attribute.h"
#include "catalog/pg_class.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "commands/dbcommands.h"
#include "commands/seclabel.h"
#include "libpq/auth.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/tqual.h"
#include "sepgsql.h"
#include <selinux/label.h>
Include dependency graph for label.c:

Go to the source code of this file.

Data Structures

struct  pending_label

Functions

char * sepgsql_get_client_label (void)
static void sepgsql_set_client_label (const char *new_label)
static void sepgsql_xact_callback (XactEvent event, void *arg)
static void sepgsql_subxact_callback (SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
static void sepgsql_client_auth (Port *port, int status)
static bool sepgsql_needs_fmgr_hook (Oid functionId)
static void sepgsql_fmgr_hook (FmgrHookEventType event, FmgrInfo *flinfo, Datum *private)
void sepgsql_init_client_label (void)
char * sepgsql_get_label (Oid classId, Oid objectId, int32 subId)
void sepgsql_object_relabel (const ObjectAddress *object, const char *seclabel)
 PG_FUNCTION_INFO_V1 (sepgsql_getcon)
Datum sepgsql_getcon (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (sepgsql_setcon)
Datum sepgsql_setcon (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (sepgsql_mcstrans_in)
Datum sepgsql_mcstrans_in (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (sepgsql_mcstrans_out)
Datum sepgsql_mcstrans_out (PG_FUNCTION_ARGS)
static char * quote_object_name (const char *src1, const char *src2, const char *src3, const char *src4)
static void exec_object_restorecon (struct selabel_handle *sehnd, Oid catalogId)
 PG_FUNCTION_INFO_V1 (sepgsql_restorecon)
Datum sepgsql_restorecon (PG_FUNCTION_ARGS)

Variables

static
ClientAuthentication_hook_type 
next_client_auth_hook = NULL
static needs_fmgr_hook_type next_needs_fmgr_hook = NULL
static fmgr_hook_type next_fmgr_hook = NULL
static char * client_label_peer = NULL
static Listclient_label_pending = NIL
static char * client_label_committed = NULL
static char * client_label_func = NULL

Function Documentation

static void exec_object_restorecon ( struct selabel_handle *  sehnd,
Oid  catalogId 
) [static]

Definition at line 714 of file label.c.

References AccessShareLock, AttributeRelationId, DatabaseRelationId, elog, ereport, errcode(), errmsg(), ERROR, get_database_name(), get_namespace_name(), get_rel_name(), get_rel_namespace(), get_rel_relkind(), GETSTRUCT, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvalidOid, MyDatabaseId, NamespaceRelationId, NameStr, NoLock, NULL, pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, ProcedureRelationId, quote_object_name(), RelationRelationId, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, SEPGSQL_LABEL_TAG, sepgsql_object_relabel(), SetSecurityLabel(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and WARNING.

Referenced by sepgsql_restorecon().

{
    Relation    rel;
    SysScanDesc sscan;
    HeapTuple   tuple;
    char       *database_name = get_database_name(MyDatabaseId);
    char       *namespace_name;
    Oid         namespace_id;
    char       *relation_name;

    /*
     * Open the target catalog. We don't want to allow writable accesses by
     * other session during initial labeling.
     */
    rel = heap_open(catalogId, AccessShareLock);

    sscan = systable_beginscan(rel, InvalidOid, false,
                               SnapshotNow, 0, NULL);
    while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
    {
        Form_pg_database datForm;
        Form_pg_namespace nspForm;
        Form_pg_class relForm;
        Form_pg_attribute attForm;
        Form_pg_proc proForm;
        char       *objname;
        int         objtype = 1234;
        ObjectAddress object;
        security_context_t context;

        /*
         * The way to determine object name depends on object classes. So, any
         * branches set up `objtype', `objname' and `object' here.
         */
        switch (catalogId)
        {
            case DatabaseRelationId:
                datForm = (Form_pg_database) GETSTRUCT(tuple);

                objtype = SELABEL_DB_DATABASE;

                objname = quote_object_name(NameStr(datForm->datname),
                                            NULL, NULL, NULL);

                object.classId = DatabaseRelationId;
                object.objectId = HeapTupleGetOid(tuple);
                object.objectSubId = 0;
                break;

            case NamespaceRelationId:
                nspForm = (Form_pg_namespace) GETSTRUCT(tuple);

                objtype = SELABEL_DB_SCHEMA;

                objname = quote_object_name(database_name,
                                            NameStr(nspForm->nspname),
                                            NULL, NULL);

                object.classId = NamespaceRelationId;
                object.objectId = HeapTupleGetOid(tuple);
                object.objectSubId = 0;
                break;

            case RelationRelationId:
                relForm = (Form_pg_class) GETSTRUCT(tuple);

                if (relForm->relkind == RELKIND_RELATION)
                    objtype = SELABEL_DB_TABLE;
                else if (relForm->relkind == RELKIND_SEQUENCE)
                    objtype = SELABEL_DB_SEQUENCE;
                else if (relForm->relkind == RELKIND_VIEW)
                    objtype = SELABEL_DB_VIEW;
                else
                    continue;   /* no need to assign security label */

                namespace_name = get_namespace_name(relForm->relnamespace);
                objname = quote_object_name(database_name,
                                            namespace_name,
                                            NameStr(relForm->relname),
                                            NULL);
                pfree(namespace_name);

                object.classId = RelationRelationId;
                object.objectId = HeapTupleGetOid(tuple);
                object.objectSubId = 0;
                break;

            case AttributeRelationId:
                attForm = (Form_pg_attribute) GETSTRUCT(tuple);

                if (get_rel_relkind(attForm->attrelid) != RELKIND_RELATION)
                    continue;   /* no need to assign security label */

                objtype = SELABEL_DB_COLUMN;

                namespace_id = get_rel_namespace(attForm->attrelid);
                namespace_name = get_namespace_name(namespace_id);
                relation_name = get_rel_name(attForm->attrelid);
                objname = quote_object_name(database_name,
                                            namespace_name,
                                            relation_name,
                                            NameStr(attForm->attname));
                pfree(namespace_name);
                pfree(relation_name);

                object.classId = RelationRelationId;
                object.objectId = attForm->attrelid;
                object.objectSubId = attForm->attnum;
                break;

            case ProcedureRelationId:
                proForm = (Form_pg_proc) GETSTRUCT(tuple);

                objtype = SELABEL_DB_PROCEDURE;

                namespace_name = get_namespace_name(proForm->pronamespace);
                objname = quote_object_name(database_name,
                                            namespace_name,
                                            NameStr(proForm->proname),
                                            NULL);
                pfree(namespace_name);

                object.classId = ProcedureRelationId;
                object.objectId = HeapTupleGetOid(tuple);
                object.objectSubId = 0;
                break;

            default:
                elog(ERROR, "unexpected catalog id: %u", catalogId);
                objname = NULL; /* for compiler quiet */
                break;
        }

        if (selabel_lookup_raw(sehnd, &context, objname, objtype) == 0)
        {
            PG_TRY();
            {
                /*
                 * Check SELinux permission to relabel the fetched object,
                 * then do the actual relabeling.
                 */
                sepgsql_object_relabel(&object, context);

                SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, context);
            }
            PG_CATCH();
            {
                freecon(context);
                PG_RE_THROW();
            }
            PG_END_TRY();
            freecon(context);
        }
        else if (errno == ENOENT)
            ereport(WARNING,
                    (errmsg("SELinux: no initial label assigned for %s (type=%d), skipping",
                            objname, objtype)));
        else
            ereport(ERROR,
                    (errcode(ERRCODE_INTERNAL_ERROR),
                     errmsg("SELinux: could not determine initial security label for %s (type=%d): %m", objname, objtype)));

        pfree(objname);
    }
    systable_endscan(sscan);

    heap_close(rel, NoLock);
}

PG_FUNCTION_INFO_V1 ( sepgsql_getcon   ) 
PG_FUNCTION_INFO_V1 ( sepgsql_mcstrans_out   ) 
PG_FUNCTION_INFO_V1 ( sepgsql_restorecon   ) 
PG_FUNCTION_INFO_V1 ( sepgsql_setcon   ) 
PG_FUNCTION_INFO_V1 ( sepgsql_mcstrans_in   ) 
static char* quote_object_name ( const char *  src1,
const char *  src2,
const char *  src3,
const char *  src4 
) [static]

Definition at line 667 of file label.c.

References appendStringInfo(), StringInfoData::data, initStringInfo(), pfree(), and quote_identifier().

Referenced by exec_object_restorecon().

{
    StringInfoData result;
    const char *temp;

    initStringInfo(&result);

    if (src1)
    {
        temp = quote_identifier(src1);
        appendStringInfo(&result, "%s", temp);
        if (src1 != temp)
            pfree((void *) temp);
    }
    if (src2)
    {
        temp = quote_identifier(src2);
        appendStringInfo(&result, ".%s", temp);
        if (src2 != temp)
            pfree((void *) temp);
    }
    if (src3)
    {
        temp = quote_identifier(src3);
        appendStringInfo(&result, ".%s", temp);
        if (src3 != temp)
            pfree((void *) temp);
    }
    if (src4)
    {
        temp = quote_identifier(src4);
        appendStringInfo(&result, ".%s", temp);
        if (src4 != temp)
            pfree((void *) temp);
    }
    return result.data;
}

static void sepgsql_client_auth ( Port port,
int  status 
) [static]

Definition at line 240 of file label.c.

References client_label_peer, ereport, errcode(), errmsg(), FATAL, next_client_auth_hook, sepgsql_get_permissive(), SEPGSQL_MODE_DEFAULT, SEPGSQL_MODE_PERMISSIVE, sepgsql_set_mode(), and STATUS_OK.

{
    if (next_client_auth_hook)
        (*next_client_auth_hook) (port, status);

    /*
     * In the case when authentication failed, the supplied socket shall be
     * closed soon, so we don't need to do anything here.
     */
    if (status != STATUS_OK)
        return;

    /*
     * Getting security label of the peer process using API of libselinux.
     */
    if (getpeercon_raw(port->sock, &client_label_peer) < 0)
        ereport(FATAL,
                (errcode(ERRCODE_INTERNAL_ERROR),
                 errmsg("SELinux: unable to get peer label: %m")));

    /*
     * Switch the current performing mode from INTERNAL to either DEFAULT or
     * PERMISSIVE.
     */
    if (sepgsql_get_permissive())
        sepgsql_set_mode(SEPGSQL_MODE_PERMISSIVE);
    else
        sepgsql_set_mode(SEPGSQL_MODE_DEFAULT);
}

static void sepgsql_fmgr_hook ( FmgrHookEventType  event,
FmgrInfo flinfo,
Datum private 
) [static]

Definition at line 321 of file label.c.

References Assert, client_label_func, DatumGetPointer, elog, ERROR, FHET_ABORT, FHET_END, FHET_START, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, getObjectDescription(), MemoryContextSwitchTo(), next_fmgr_hook, NULL, palloc(), PointerGetDatum, SEPG_CLASS_DB_PROCEDURE, SEPG_CLASS_PROCESS, SEPG_DB_PROCEDURE__ENTRYPOINT, SEPG_PROCESS__TRANSITION, sepgsql_avc_check_perms(), sepgsql_avc_check_perms_label(), and sepgsql_avc_trusted_proc().

{
    struct
    {
        char       *old_label;
        char       *new_label;
        Datum       next_private;
    }          *stack;

    switch (event)
    {
        case FHET_START:
            stack = (void *) DatumGetPointer(*private);
            if (!stack)
            {
                MemoryContext oldcxt;

                oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
                stack = palloc(sizeof(*stack));
                stack->old_label = NULL;
                stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
                stack->next_private = 0;

                MemoryContextSwitchTo(oldcxt);

                /*
                 * process:transition permission between old and new label,
                 * when user tries to switch security label of the client on
                 * execution of trusted procedure.
                 *
                 * Also, db_procedure:entrypoint permission should be checked
                 * whether this procedure can perform as an entrypoint of the
                 * trusted procedure, or not.
                 * Note that db_procedure:execute permission shall be checked
                 * individually.
                 */
                if (stack->new_label)
                {
                    ObjectAddress object;

                    object.classId = ProcedureRelationId;
                    object.objectId = flinfo->fn_oid;
                    object.objectSubId = 0;
                    sepgsql_avc_check_perms(&object,
                                            SEPG_CLASS_DB_PROCEDURE,
                                            SEPG_DB_PROCEDURE__ENTRYPOINT,
                                            getObjectDescription(&object),
                                            true);

                    sepgsql_avc_check_perms_label(stack->new_label,
                                                  SEPG_CLASS_PROCESS,
                                                  SEPG_PROCESS__TRANSITION,
                                                  NULL, true);
                }
                *private = PointerGetDatum(stack);
            }
            Assert(!stack->old_label);
            if (stack->new_label)
            {
                stack->old_label = client_label_func;
                client_label_func = stack->new_label;
            }
            if (next_fmgr_hook)
                (*next_fmgr_hook) (event, flinfo, &stack->next_private);
            break;

        case FHET_END:
        case FHET_ABORT:
            stack = (void *) DatumGetPointer(*private);

            if (next_fmgr_hook)
                (*next_fmgr_hook) (event, flinfo, &stack->next_private);

            if (stack->new_label)
            {
                client_label_func = stack->old_label;
                stack->old_label = NULL;
            }
            break;

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

char* sepgsql_get_client_label ( void   ) 
char* sepgsql_get_label ( Oid  classId,
Oid  objectId,
int32  subId 
)

Definition at line 456 of file label.c.

References ereport, errcode(), errmsg(), ERROR, GetSecurityLabel(), label, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pstrdup(), and SEPGSQL_LABEL_TAG.

Referenced by sepgsql_attribute_post_create(), sepgsql_database_post_create(), sepgsql_proc_post_create(), sepgsql_relation_post_create(), and sepgsql_schema_post_create().

{
    ObjectAddress object;
    char       *label;

    object.classId = classId;
    object.objectId = objectId;
    object.objectSubId = subId;

    label = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG);
    if (!label || security_check_context_raw((security_context_t) label))
    {
        security_context_t unlabeled;

        if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
            ereport(ERROR,
                    (errcode(ERRCODE_INTERNAL_ERROR),
               errmsg("SELinux: failed to get initial security label: %m")));
        PG_TRY();
        {
            label = pstrdup(unlabeled);
        }
        PG_CATCH();
        {
            freecon(unlabeled);
            PG_RE_THROW();
        }
        PG_END_TRY();

        freecon(unlabeled);
    }
    return label;
}

Datum sepgsql_getcon ( PG_FUNCTION_ARGS   ) 

Definition at line 548 of file label.c.

References cstring_to_text(), PG_RETURN_NULL, PG_RETURN_TEXT_P, sepgsql_get_client_label(), and sepgsql_is_enabled().

{
    char       *client_label;

    if (!sepgsql_is_enabled())
        PG_RETURN_NULL();

    client_label = sepgsql_get_client_label();

    PG_RETURN_TEXT_P(cstring_to_text(client_label));
}

void sepgsql_init_client_label ( void   ) 

Definition at line 415 of file label.c.

References client_label_peer, ClientAuthentication_hook, ereport, errcode(), errmsg(), ERROR, fmgr_hook, needs_fmgr_hook, next_client_auth_hook, next_fmgr_hook, next_needs_fmgr_hook, NULL, RegisterSubXactCallback(), RegisterXactCallback(), sepgsql_subxact_callback(), and sepgsql_xact_callback().

Referenced by _PG_init().

{
    /*
     * Set up dummy client label.
     *
     * XXX - note that PostgreSQL launches background worker process like
     * autovacuum without authentication steps. So, we initialize sepgsql_mode
     * with SEPGSQL_MODE_INTERNAL, and client_label with the security context
     * of server process. Later, it also launches background of user session.
     * In this case, the process is always hooked on post-authentication, and
     * we can initialize the sepgsql_mode and client_label correctly.
     */
    if (getcon_raw(&client_label_peer) < 0)
        ereport(ERROR,
                (errcode(ERRCODE_INTERNAL_ERROR),
                 errmsg("SELinux: failed to get server security label: %m")));

    /* Client authentication hook */
    next_client_auth_hook = ClientAuthentication_hook;
    ClientAuthentication_hook = sepgsql_client_auth;

    /* Trusted procedure hooks */
    next_needs_fmgr_hook = needs_fmgr_hook;
    needs_fmgr_hook = sepgsql_needs_fmgr_hook;

    next_fmgr_hook = fmgr_hook;
    fmgr_hook = sepgsql_fmgr_hook;

    /* Transaction/Sub-transaction callbacks */
    RegisterXactCallback(sepgsql_xact_callback, NULL);
    RegisterSubXactCallback(sepgsql_subxact_callback, NULL);
}

Datum sepgsql_mcstrans_in ( PG_FUNCTION_ARGS   ) 

Definition at line 589 of file label.c.

References cstring_to_text(), ereport, errcode(), errmsg(), ERROR, label, PG_CATCH, PG_END_TRY, PG_GETARG_TEXT_P, PG_RE_THROW, PG_RETURN_TEXT_P, PG_TRY, pstrdup(), sepgsql_is_enabled(), and text_to_cstring().

{
    text       *label = PG_GETARG_TEXT_P(0);
    char       *raw_label;
    char       *result;

    if (!sepgsql_is_enabled())
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("sepgsql is not enabled")));

    if (selinux_trans_to_raw_context(text_to_cstring(label),
                                     &raw_label) < 0)
        ereport(ERROR,
                (errcode(ERRCODE_INTERNAL_ERROR),
                 errmsg("SELinux: could not translate security label: %m")));

    PG_TRY();
    {
        result = pstrdup(raw_label);
    }
    PG_CATCH();
    {
        freecon(raw_label);
        PG_RE_THROW();
    }
    PG_END_TRY();
    freecon(raw_label);

    PG_RETURN_TEXT_P(cstring_to_text(result));
}

Datum sepgsql_mcstrans_out ( PG_FUNCTION_ARGS   ) 

Definition at line 629 of file label.c.

References cstring_to_text(), ereport, errcode(), errmsg(), ERROR, label, PG_CATCH, PG_END_TRY, PG_GETARG_TEXT_P, PG_RE_THROW, PG_RETURN_TEXT_P, PG_TRY, pstrdup(), sepgsql_is_enabled(), and text_to_cstring().

{
    text       *label = PG_GETARG_TEXT_P(0);
    char       *qual_label;
    char       *result;

    if (!sepgsql_is_enabled())
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("sepgsql is not currently enabled")));

    if (selinux_raw_to_trans_context(text_to_cstring(label),
                                     &qual_label) < 0)
        ereport(ERROR,
                (errcode(ERRCODE_INTERNAL_ERROR),
                 errmsg("SELinux: could not translate security label: %m")));

    PG_TRY();
    {
        result = pstrdup(qual_label);
    }
    PG_CATCH();
    {
        freecon(qual_label);
        PG_RE_THROW();
    }
    PG_END_TRY();
    freecon(qual_label);

    PG_RETURN_TEXT_P(cstring_to_text(result));
}

static bool sepgsql_needs_fmgr_hook ( Oid  functionId  )  [static]

Definition at line 278 of file label.c.

References next_needs_fmgr_hook, NULL, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__ENTRYPOINT, SEPG_DB_PROCEDURE__EXECUTE, sepgsql_avc_check_perms(), SEPGSQL_AVC_NOAUDIT, and sepgsql_avc_trusted_proc().

{
    ObjectAddress object;

    if (next_needs_fmgr_hook &&
        (*next_needs_fmgr_hook) (functionId))
        return true;

    /*
     * SELinux needs the function to be called via security_definer wrapper,
     * if this invocation will take a domain-transition. We call these
     * functions as trusted-procedure, if the security policy has a rule that
     * switches security label of the client on execution.
     */
    if (sepgsql_avc_trusted_proc(functionId) != NULL)
        return true;

    /*
     * Even if not a trusted-procedure, this function should not be inlined
     * unless the client has db_procedure:{execute} permission. Please note
     * that it shall be actually failed later because of same reason with
     * ACL_EXECUTE.
     */
    object.classId = ProcedureRelationId;
    object.objectId = functionId;
    object.objectSubId = 0;
    if (!sepgsql_avc_check_perms(&object,
                                 SEPG_CLASS_DB_PROCEDURE,
                                 SEPG_DB_PROCEDURE__EXECUTE |
                                 SEPG_DB_PROCEDURE__ENTRYPOINT,
                                 SEPGSQL_AVC_NOAUDIT, false))
        return true;

    return false;
}

void sepgsql_object_relabel ( const ObjectAddress object,
const char *  seclabel 
)

Definition at line 496 of file label.c.

References ObjectAddress::classId, DatabaseRelationId, elog, ereport, errcode(), errmsg(), ERROR, NamespaceRelationId, ObjectAddress::objectId, ObjectAddress::objectSubId, ProcedureRelationId, RelationRelationId, sepgsql_attribute_relabel(), sepgsql_database_relabel(), sepgsql_proc_relabel(), sepgsql_relation_relabel(), and sepgsql_schema_relabel().

Referenced by _PG_init(), and exec_object_restorecon().

{
    /*
     * validate format of the supplied security label, if it is security
     * context of selinux.
     */
    if (seclabel &&
        security_check_context_raw((security_context_t) seclabel) < 0)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_NAME),
               errmsg("SELinux: invalid security label: \"%s\"", seclabel)));

    /*
     * Do actual permission checks for each object classes
     */
    switch (object->classId)
    {
        case DatabaseRelationId:
            sepgsql_database_relabel(object->objectId, seclabel);
            break;

        case NamespaceRelationId:
            sepgsql_schema_relabel(object->objectId, seclabel);
            break;

        case RelationRelationId:
            if (object->objectSubId == 0)
                sepgsql_relation_relabel(object->objectId,
                                         seclabel);
            else
                sepgsql_attribute_relabel(object->objectId,
                                          object->objectSubId,
                                          seclabel);
            break;

        case ProcedureRelationId:
            sepgsql_proc_relabel(object->objectId, seclabel);
            break;

        default:
            elog(ERROR, "unsupported object type: %u", object->classId);
            break;
    }
}

Datum sepgsql_restorecon ( PG_FUNCTION_ARGS   ) 

Definition at line 896 of file label.c.

References AttributeRelationId, DatabaseRelationId, ereport, errcode(), errmsg(), ERROR, exec_object_restorecon(), NamespaceRelationId, PG_ARGISNULL, PG_CATCH, PG_END_TRY, PG_GETARG_DATUM, PG_RE_THROW, PG_RETURN_BOOL, PG_TRY, ProcedureRelationId, RelationRelationId, sepgsql_is_enabled(), superuser(), and TextDatumGetCString.

{
    struct selabel_handle *sehnd;
    struct selinux_opt seopts;

    /*
     * SELinux has to be enabled on the running platform.
     */
    if (!sepgsql_is_enabled())
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("sepgsql is not currently enabled")));

    /*
     * Check DAC permission. Only superuser can set up initial security
     * labels, like root-user in filesystems
     */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
          errmsg("SELinux: must be superuser to restore initial contexts")));

    /*
     * Open selabel_lookup(3) stuff. It provides a set of mapping between an
     * initial security label and object class/name due to the system setting.
     */
    if (PG_ARGISNULL(0))
    {
        seopts.type = SELABEL_OPT_UNUSED;
        seopts.value = NULL;
    }
    else
    {
        seopts.type = SELABEL_OPT_PATH;
        seopts.value = TextDatumGetCString(PG_GETARG_DATUM(0));
    }
    sehnd = selabel_open(SELABEL_CTX_DB, &seopts, 1);
    if (!sehnd)
        ereport(ERROR,
                (errcode(ERRCODE_INTERNAL_ERROR),
               errmsg("SELinux: failed to initialize labeling handle: %m")));
    PG_TRY();
    {
        exec_object_restorecon(sehnd, DatabaseRelationId);
        exec_object_restorecon(sehnd, NamespaceRelationId);
        exec_object_restorecon(sehnd, RelationRelationId);
        exec_object_restorecon(sehnd, AttributeRelationId);
        exec_object_restorecon(sehnd, ProcedureRelationId);
    }
    PG_CATCH();
    {
        selabel_close(sehnd);
        PG_RE_THROW();
    }
    PG_END_TRY();

    selabel_close(sehnd);

    PG_RETURN_BOOL(true);
}

static void sepgsql_set_client_label ( const char *  new_label  )  [static]

Definition at line 114 of file label.c.

References client_label_peer, CurTransactionContext, ereport, errcode(), errmsg(), ERROR, GetCurrentSubTransactionId(), pending_label::label, lappend(), MemoryContextSwitchTo(), NULL, palloc0(), pstrdup(), SEPG_CLASS_PROCESS, SEPG_PROCESS__DYNTRANSITION, SEPG_PROCESS__SETCURRENT, sepgsql_avc_check_perms_label(), sepgsql_get_client_label(), and pending_label::subid.

Referenced by sepgsql_setcon().

{
    const char *tcontext;
    MemoryContext oldcxt;
    pending_label *plabel;

    /* Reset to the initial client label, if NULL */
    if (!new_label)
        tcontext = client_label_peer;
    else
    {
        if (security_check_context_raw((security_context_t) new_label) < 0)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_NAME),
                     errmsg("SELinux: invalid security label: \"%s\"",
                            new_label)));
        tcontext = new_label;
    }

    /* Check process:{setcurrent} permission. */
    sepgsql_avc_check_perms_label(sepgsql_get_client_label(),
                                  SEPG_CLASS_PROCESS,
                                  SEPG_PROCESS__SETCURRENT,
                                  NULL,
                                  true);
    /* Check process:{dyntransition} permission. */
    sepgsql_avc_check_perms_label(tcontext,
                                  SEPG_CLASS_PROCESS,
                                  SEPG_PROCESS__DYNTRANSITION,
                                  NULL,
                                  true);

    /*
     * Append the supplied new_label on the pending list until the current
     * transaction is committed.
     */
    oldcxt = MemoryContextSwitchTo(CurTransactionContext);

    plabel = palloc0(sizeof(pending_label));
    plabel->subid = GetCurrentSubTransactionId();
    if (new_label)
        plabel->label = pstrdup(new_label);
    client_label_pending = lappend(client_label_pending, plabel);

    MemoryContextSwitchTo(oldcxt);
}

Datum sepgsql_setcon ( PG_FUNCTION_ARGS   ) 

Definition at line 567 of file label.c.

References PG_ARGISNULL, PG_GETARG_DATUM, PG_RETURN_BOOL, sepgsql_set_client_label(), and TextDatumGetCString.

{
    const char *new_label;

    if (PG_ARGISNULL(0))
        new_label = NULL;
    else
        new_label = TextDatumGetCString(PG_GETARG_DATUM(0));

    sepgsql_set_client_label(new_label);

    PG_RETURN_BOOL(true);
}

static void sepgsql_subxact_callback ( SubXactEvent  event,
SubTransactionId  mySubid,
SubTransactionId  parentSubid,
void *  arg 
) [static]

Definition at line 207 of file label.c.

References lfirst, list_delete_cell(), list_head(), lnext, pending_label::subid, and SUBXACT_EVENT_ABORT_SUB.

Referenced by sepgsql_init_client_label().

{
    ListCell   *cell;
    ListCell   *prev;
    ListCell   *next;

    if (event == SUBXACT_EVENT_ABORT_SUB)
    {
        prev = NULL;
        for (cell = list_head(client_label_pending); cell; cell = next)
        {
            pending_label *plabel = lfirst(cell);

            next = lnext(cell);

            if (plabel->subid == mySubid)
                client_label_pending
                    = list_delete_cell(client_label_pending, cell, prev);
            else
                prev = cell;
        }
    }
}

static void sepgsql_xact_callback ( XactEvent  event,
void *  arg 
) [static]

Definition at line 168 of file label.c.

References client_label_committed, pending_label::label, llast, MemoryContextStrdup(), NIL, pfree(), TopMemoryContext, XACT_EVENT_ABORT, and XACT_EVENT_COMMIT.

Referenced by sepgsql_init_client_label().

{
    if (event == XACT_EVENT_COMMIT)
    {
        if (client_label_pending != NIL)
        {
            pending_label *plabel = llast(client_label_pending);
            char       *new_label;

            if (plabel->label)
                new_label = MemoryContextStrdup(TopMemoryContext,
                                                plabel->label);
            else
                new_label = NULL;

            if (client_label_committed)
                pfree(client_label_committed);

            client_label_committed = new_label;

            /*
             * XXX - Note that items of client_label_pending are allocated on
             * CurTransactionContext, thus, all acquired memory region shall
             * be released implicitly.
             */
            client_label_pending = NIL;
        }
    }
    else if (event == XACT_EVENT_ABORT)
        client_label_pending = NIL;
}


Variable Documentation

char* client_label_committed = NULL [static]

Definition at line 65 of file label.c.

Referenced by sepgsql_get_client_label(), and sepgsql_xact_callback().

char* client_label_func = NULL [static]

Definition at line 67 of file label.c.

Referenced by sepgsql_fmgr_hook(), and sepgsql_get_client_label().

char* client_label_peer = NULL [static]
List* client_label_pending = NIL [static]

Definition at line 63 of file label.c.

Definition at line 45 of file label.c.

Referenced by sepgsql_client_auth(), and sepgsql_init_client_label().

fmgr_hook_type next_fmgr_hook = NULL [static]

Definition at line 47 of file label.c.

Referenced by sepgsql_fmgr_hook(), and sepgsql_init_client_label().

Definition at line 46 of file label.c.

Referenced by sepgsql_init_client_label(), and sepgsql_needs_fmgr_hook().