xselinux_hooks.c revision 1b5d61b8
16747b715Smrg/************************************************************
26747b715Smrg
36747b715SmrgAuthor: Eamon Walsh <ewalsh@tycho.nsa.gov>
46747b715Smrg
56747b715SmrgPermission to use, copy, modify, distribute, and sell this software and its
66747b715Smrgdocumentation for any purpose is hereby granted without fee, provided that
76747b715Smrgthis permission notice appear in supporting documentation.  This permission
86747b715Smrgnotice shall be included in all copies or substantial portions of the
96747b715SmrgSoftware.
106747b715Smrg
116747b715SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
126747b715SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
136747b715SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
146747b715SmrgAUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
156747b715SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
166747b715SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
176747b715Smrg
186747b715Smrg********************************************************/
196747b715Smrg
206747b715Smrg/*
216747b715Smrg * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc.
226747b715Smrg * All rights reserved.
236747b715Smrg */
246747b715Smrg
256747b715Smrg#ifdef HAVE_DIX_CONFIG_H
266747b715Smrg#include <dix-config.h>
276747b715Smrg#endif
286747b715Smrg
296747b715Smrg#include <sys/socket.h>
306747b715Smrg#include <stdio.h>
316747b715Smrg#include <stdarg.h>
326747b715Smrg
336747b715Smrg#include <libaudit.h>
346747b715Smrg
356747b715Smrg#include <X11/Xatom.h>
366747b715Smrg#include "selection.h"
376747b715Smrg#include "inputstr.h"
386747b715Smrg#include "scrnintstr.h"
396747b715Smrg#include "windowstr.h"
406747b715Smrg#include "propertyst.h"
416747b715Smrg#include "extnsionst.h"
426747b715Smrg#include "xacestr.h"
4335c4bbdfSmrg#include "client.h"
446747b715Smrg#define _XSELINUX_NEED_FLASK_MAP
456747b715Smrg#include "xselinuxint.h"
466747b715Smrg
476747b715Smrg/* structure passed to auditing callback */
486747b715Smrgtypedef struct {
4935c4bbdfSmrg    ClientPtr client;           /* client */
5035c4bbdfSmrg    DeviceIntPtr dev;           /* device */
5135c4bbdfSmrg    char *command;              /* client's executable path */
5235c4bbdfSmrg    unsigned id;                /* resource id, if any */
5335c4bbdfSmrg    int restype;                /* resource type, if any */
5435c4bbdfSmrg    int event;                  /* event type, if any */
5535c4bbdfSmrg    Atom property;              /* property name, if any */
5635c4bbdfSmrg    Atom selection;             /* selection name, if any */
5735c4bbdfSmrg    char *extension;            /* extension name, if any */
586747b715Smrg} SELinuxAuditRec;
596747b715Smrg
606747b715Smrg/* private state keys */
616747b715SmrgDevPrivateKeyRec subjectKeyRec;
626747b715SmrgDevPrivateKeyRec objectKeyRec;
636747b715SmrgDevPrivateKeyRec dataKeyRec;
646747b715Smrg
656747b715Smrg/* audit file descriptor */
666747b715Smrgstatic int audit_fd;
676747b715Smrg
686747b715Smrg/* atoms for window label properties */
696747b715Smrgstatic Atom atom_ctx;
706747b715Smrgstatic Atom atom_client_ctx;
716747b715Smrg
726747b715Smrg/* The unlabeled SID */
736747b715Smrgstatic security_id_t unlabeled_sid;
746747b715Smrg
756747b715Smrg/* forward declarations */
7635c4bbdfSmrgstatic void SELinuxScreen(CallbackListPtr *, void *, void *);
776747b715Smrg
786747b715Smrg/* "true" pointer value for use as callback data */
7935c4bbdfSmrgstatic void *truep = (void *) 1;
806747b715Smrg
816747b715Smrg/*
826747b715Smrg * Performs an SELinux permission check.
836747b715Smrg */
846747b715Smrgstatic int
8535c4bbdfSmrgSELinuxDoCheck(SELinuxSubjectRec * subj, SELinuxObjectRec * obj,
8635c4bbdfSmrg               security_class_t class, Mask mode, SELinuxAuditRec * auditdata)
876747b715Smrg{
886747b715Smrg    /* serverClient requests OK */
896747b715Smrg    if (subj->privileged)
9035c4bbdfSmrg        return Success;
916747b715Smrg
926747b715Smrg    auditdata->command = subj->command;
936747b715Smrg    errno = 0;
946747b715Smrg
956747b715Smrg    if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref,
9635c4bbdfSmrg                     auditdata) < 0) {
9735c4bbdfSmrg        if (mode == DixUnknownAccess)
9835c4bbdfSmrg            return Success;     /* DixUnknownAccess requests OK ... for now */
9935c4bbdfSmrg        if (errno == EACCES)
10035c4bbdfSmrg            return BadAccess;
10135c4bbdfSmrg        ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno);
10235c4bbdfSmrg        return BadValue;
1036747b715Smrg    }
1046747b715Smrg
1056747b715Smrg    return Success;
1066747b715Smrg}
1076747b715Smrg
1086747b715Smrg/*
1096747b715Smrg * Labels a newly connected client.
1106747b715Smrg */
1116747b715Smrgstatic void
1126747b715SmrgSELinuxLabelClient(ClientPtr client)
1136747b715Smrg{
1146747b715Smrg    int fd = XaceGetConnectionNumber(client);
1156747b715Smrg    SELinuxSubjectRec *subj;
1166747b715Smrg    SELinuxObjectRec *obj;
1176747b715Smrg    security_context_t ctx;
1186747b715Smrg
1196747b715Smrg    subj = dixLookupPrivate(&client->devPrivates, subjectKey);
1206747b715Smrg    obj = dixLookupPrivate(&client->devPrivates, objectKey);
1216747b715Smrg
1226747b715Smrg    /* Try to get a context from the socket */
1236747b715Smrg    if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) {
12435c4bbdfSmrg        /* Otherwise, fall back to a default context */
12535c4bbdfSmrg        ctx = SELinuxDefaultClientLabel();
1266747b715Smrg    }
1276747b715Smrg
1286747b715Smrg    /* For local clients, try and determine the executable name */
1296747b715Smrg    if (XaceIsLocal(client)) {
13035c4bbdfSmrg        /* Get cached command name if CLIENTIDS is enabled. */
13135c4bbdfSmrg        const char *cmdname = GetClientCmdName(client);
13235c4bbdfSmrg        Bool cached = (cmdname != NULL);
13335c4bbdfSmrg
13435c4bbdfSmrg        /* If CLIENTIDS is disabled, figure out the command name from
13535c4bbdfSmrg         * scratch. */
13635c4bbdfSmrg        if (!cmdname) {
13735c4bbdfSmrg            pid_t pid = DetermineClientPid(client);
13835c4bbdfSmrg
13935c4bbdfSmrg            if (pid != -1)
14035c4bbdfSmrg                DetermineClientCmd(pid, &cmdname, NULL);
14135c4bbdfSmrg        }
14235c4bbdfSmrg
14335c4bbdfSmrg        if (!cmdname)
14435c4bbdfSmrg            goto finish;
14535c4bbdfSmrg
14635c4bbdfSmrg        strncpy(subj->command, cmdname, COMMAND_LEN - 1);
14735c4bbdfSmrg
14835c4bbdfSmrg        if (!cached)
14935c4bbdfSmrg            free((void *) cmdname);     /* const char * */
1506747b715Smrg    }
1516747b715Smrg
15235c4bbdfSmrg finish:
1536747b715Smrg    /* Get a SID from the context */
1546747b715Smrg    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
15535c4bbdfSmrg        FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n",
15635c4bbdfSmrg                   client->index, ctx);
1576747b715Smrg
1586747b715Smrg    obj->sid = subj->sid;
1596747b715Smrg    freecon(ctx);
1606747b715Smrg}
1616747b715Smrg
1626747b715Smrg/*
1636747b715Smrg * Labels initial server objects.
1646747b715Smrg */
1656747b715Smrgstatic void
1666747b715SmrgSELinuxLabelInitial(void)
1676747b715Smrg{
1686747b715Smrg    int i;
1696747b715Smrg    XaceScreenAccessRec srec;
1706747b715Smrg    SELinuxSubjectRec *subj;
1716747b715Smrg    SELinuxObjectRec *obj;
1726747b715Smrg    security_context_t ctx;
17335c4bbdfSmrg    void *unused;
1746747b715Smrg
1756747b715Smrg    /* Do the serverClient */
1766747b715Smrg    subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
1776747b715Smrg    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
1786747b715Smrg    subj->privileged = 1;
1796747b715Smrg
1806747b715Smrg    /* Use the context of the X server process for the serverClient */
1816747b715Smrg    if (getcon_raw(&ctx) < 0)
18235c4bbdfSmrg        FatalError("SELinux: couldn't get context of X server process\n");
1836747b715Smrg
1846747b715Smrg    /* Get a SID from the context */
1856747b715Smrg    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
18635c4bbdfSmrg        FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx);
1876747b715Smrg
1886747b715Smrg    obj->sid = subj->sid;
1896747b715Smrg    freecon(ctx);
1906747b715Smrg
1916747b715Smrg    srec.client = serverClient;
1926747b715Smrg    srec.access_mode = DixCreateAccess;
1936747b715Smrg    srec.status = Success;
1946747b715Smrg
1956747b715Smrg    for (i = 0; i < screenInfo.numScreens; i++) {
19635c4bbdfSmrg        /* Do the screen object */
19735c4bbdfSmrg        srec.screen = screenInfo.screens[i];
19835c4bbdfSmrg        SELinuxScreen(NULL, NULL, &srec);
1996747b715Smrg
20035c4bbdfSmrg        /* Do the default colormap */
20135c4bbdfSmrg        dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap,
20235c4bbdfSmrg                                RT_COLORMAP, serverClient, DixCreateAccess);
2036747b715Smrg    }
2046747b715Smrg}
2056747b715Smrg
2066747b715Smrg/*
2076747b715Smrg * Labels new resource objects.
2086747b715Smrg */
2096747b715Smrgstatic int
21035c4bbdfSmrgSELinuxLabelResource(XaceResourceAccessRec * rec, SELinuxSubjectRec * subj,
21135c4bbdfSmrg                     SELinuxObjectRec * obj, security_class_t class)
2126747b715Smrg{
2136747b715Smrg    int offset;
2146747b715Smrg    security_id_t tsid;
2156747b715Smrg
2166747b715Smrg    /* Check for a create context */
2176747b715Smrg    if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) {
21835c4bbdfSmrg        obj->sid = subj->win_create_sid;
21935c4bbdfSmrg        return Success;
2206747b715Smrg    }
2216747b715Smrg
2226747b715Smrg    if (rec->parent)
22335c4bbdfSmrg        offset = dixLookupPrivateOffset(rec->ptype);
2246747b715Smrg
2256747b715Smrg    if (rec->parent && offset >= 0) {
22635c4bbdfSmrg        /* Use the SID of the parent object in the labeling operation */
22735c4bbdfSmrg        PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset);
22835c4bbdfSmrg        SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey);
22935c4bbdfSmrg
23035c4bbdfSmrg        tsid = pobj->sid;
23135c4bbdfSmrg    }
23235c4bbdfSmrg    else {
23335c4bbdfSmrg        /* Use the SID of the subject */
23435c4bbdfSmrg        tsid = subj->sid;
2356747b715Smrg    }
2366747b715Smrg
2376747b715Smrg    /* Perform a transition to obtain the final SID */
2386747b715Smrg    if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) {
23935c4bbdfSmrg        ErrorF("SELinux: a compute_create call failed!\n");
24035c4bbdfSmrg        return BadValue;
2416747b715Smrg    }
2426747b715Smrg
2436747b715Smrg    return Success;
2446747b715Smrg}
2456747b715Smrg
2466747b715Smrg/*
2476747b715Smrg * Libselinux Callbacks
2486747b715Smrg */
2496747b715Smrg
2506747b715Smrgstatic int
2516747b715SmrgSELinuxAudit(void *auditdata,
25235c4bbdfSmrg             security_class_t class, char *msgbuf, size_t msgbufsize)
2536747b715Smrg{
2546747b715Smrg    SELinuxAuditRec *audit = auditdata;
2556747b715Smrg    ClientPtr client = audit->client;
2566747b715Smrg    char idNum[16];
2576747b715Smrg    const char *propertyName, *selectionName;
2586747b715Smrg    int major = -1, minor = -1;
2596747b715Smrg
2606747b715Smrg    if (client) {
26135c4bbdfSmrg        REQUEST(xReq);
26235c4bbdfSmrg        if (stuff) {
26335c4bbdfSmrg            major = client->majorOp;
26435c4bbdfSmrg            minor = client->minorOp;
26535c4bbdfSmrg        }
2666747b715Smrg    }
2676747b715Smrg    if (audit->id)
26835c4bbdfSmrg        snprintf(idNum, 16, "%x", audit->id);
2696747b715Smrg
2706747b715Smrg    propertyName = audit->property ? NameForAtom(audit->property) : NULL;
2716747b715Smrg    selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
2726747b715Smrg
2736747b715Smrg    return snprintf(msgbuf, msgbufsize,
27435c4bbdfSmrg                    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
27535c4bbdfSmrg                    (major >= 0) ? "request=" : "",
27635c4bbdfSmrg                    (major >= 0) ? LookupRequestName(major, minor) : "",
27735c4bbdfSmrg                    audit->command ? " comm=" : "",
27835c4bbdfSmrg                    audit->command ? audit->command : "",
27935c4bbdfSmrg                    audit->dev ? " xdevice=\"" : "",
28035c4bbdfSmrg                    audit->dev ? audit->dev->name : "",
28135c4bbdfSmrg                    audit->dev ? "\"" : "",
28235c4bbdfSmrg                    audit->id ? " resid=" : "",
28335c4bbdfSmrg                    audit->id ? idNum : "",
28435c4bbdfSmrg                    audit->restype ? " restype=" : "",
28535c4bbdfSmrg                    audit->restype ? LookupResourceName(audit->restype) : "",
28635c4bbdfSmrg                    audit->event ? " event=" : "",
28735c4bbdfSmrg                    audit->event ? LookupEventName(audit->event & 127) : "",
28835c4bbdfSmrg                    audit->property ? " property=" : "",
28935c4bbdfSmrg                    audit->property ? propertyName : "",
29035c4bbdfSmrg                    audit->selection ? " selection=" : "",
29135c4bbdfSmrg                    audit->selection ? selectionName : "",
29235c4bbdfSmrg                    audit->extension ? " extension=" : "",
29335c4bbdfSmrg                    audit->extension ? audit->extension : "");
2946747b715Smrg}
2956747b715Smrg
29635c4bbdfSmrgstatic int
29735c4bbdfSmrgSELinuxLog(int type, const char *fmt, ...) _X_ATTRIBUTE_PRINTF(2, 3);
29835c4bbdfSmrg
2996747b715Smrgstatic int
3006747b715SmrgSELinuxLog(int type, const char *fmt, ...)
3016747b715Smrg{
3026747b715Smrg    va_list ap;
3036747b715Smrg    char buf[MAX_AUDIT_MESSAGE_LENGTH];
3046747b715Smrg    int rc, aut;
3056747b715Smrg
3066747b715Smrg    switch (type) {
3076747b715Smrg    case SELINUX_INFO:
30835c4bbdfSmrg        aut = AUDIT_USER_MAC_POLICY_LOAD;
30935c4bbdfSmrg        break;
3106747b715Smrg    case SELINUX_AVC:
31135c4bbdfSmrg        aut = AUDIT_USER_AVC;
31235c4bbdfSmrg        break;
3136747b715Smrg    default:
31435c4bbdfSmrg        aut = AUDIT_USER_SELINUX_ERR;
31535c4bbdfSmrg        break;
3166747b715Smrg    }
3176747b715Smrg
3186747b715Smrg    va_start(ap, fmt);
3196747b715Smrg    vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap);
3206747b715Smrg    rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0);
32135c4bbdfSmrg    (void) rc;
3226747b715Smrg    va_end(ap);
3236747b715Smrg    LogMessageVerb(X_WARNING, 0, "%s", buf);
3246747b715Smrg    return 0;
3256747b715Smrg}
3266747b715Smrg
3276747b715Smrg/*
3286747b715Smrg * XACE Callbacks
3296747b715Smrg */
3306747b715Smrg
3316747b715Smrgstatic void
33235c4bbdfSmrgSELinuxDevice(CallbackListPtr *pcbl, void *unused, void *calldata)
3336747b715Smrg{
3346747b715Smrg    XaceDeviceAccessRec *rec = calldata;
3356747b715Smrg    SELinuxSubjectRec *subj;
3366747b715Smrg    SELinuxObjectRec *obj;
33735c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client,.dev = rec->dev };
3386747b715Smrg    security_class_t cls;
3396747b715Smrg    int rc;
3406747b715Smrg
3416747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
3426747b715Smrg    obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey);
3436747b715Smrg
3446747b715Smrg    /* If this is a new object that needs labeling, do it now */
3456747b715Smrg    if (rec->access_mode & DixCreateAccess) {
34635c4bbdfSmrg        SELinuxSubjectRec *dsubj;
34735c4bbdfSmrg
34835c4bbdfSmrg        dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
34935c4bbdfSmrg
35035c4bbdfSmrg        if (subj->dev_create_sid) {
35135c4bbdfSmrg            /* Label the device with the create context */
35235c4bbdfSmrg            obj->sid = subj->dev_create_sid;
35335c4bbdfSmrg            dsubj->sid = subj->dev_create_sid;
35435c4bbdfSmrg        }
35535c4bbdfSmrg        else {
35635c4bbdfSmrg            /* Label the device directly with the process SID */
35735c4bbdfSmrg            obj->sid = subj->sid;
35835c4bbdfSmrg            dsubj->sid = subj->sid;
35935c4bbdfSmrg        }
3606747b715Smrg    }
3616747b715Smrg
3626747b715Smrg    cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD;
3636747b715Smrg    rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata);
3646747b715Smrg    if (rc != Success)
36535c4bbdfSmrg        rec->status = rc;
3666747b715Smrg}
3676747b715Smrg
3686747b715Smrgstatic void
36935c4bbdfSmrgSELinuxSend(CallbackListPtr *pcbl, void *unused, void *calldata)
3706747b715Smrg{
3716747b715Smrg    XaceSendAccessRec *rec = calldata;
3726747b715Smrg    SELinuxSubjectRec *subj;
3736747b715Smrg    SELinuxObjectRec *obj, ev_sid;
37435c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client,.dev = rec->dev };
3756747b715Smrg    security_class_t class;
3766747b715Smrg    int rc, i, type;
3776747b715Smrg
3786747b715Smrg    if (rec->dev)
37935c4bbdfSmrg        subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
3806747b715Smrg    else
38135c4bbdfSmrg        subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
3826747b715Smrg
3836747b715Smrg    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
3846747b715Smrg
3856747b715Smrg    /* Check send permission on window */
3866747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess,
38735c4bbdfSmrg                        &auditdata);
3886747b715Smrg    if (rc != Success)
38935c4bbdfSmrg        goto err;
3906747b715Smrg
3916747b715Smrg    /* Check send permission on specific event types */
3926747b715Smrg    for (i = 0; i < rec->count; i++) {
39335c4bbdfSmrg        type = rec->events[i].u.u.type;
39435c4bbdfSmrg        class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
3956747b715Smrg
39635c4bbdfSmrg        rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
39735c4bbdfSmrg        if (rc != Success)
39835c4bbdfSmrg            goto err;
3996747b715Smrg
40035c4bbdfSmrg        auditdata.event = type;
40135c4bbdfSmrg        rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata);
40235c4bbdfSmrg        if (rc != Success)
40335c4bbdfSmrg            goto err;
4046747b715Smrg    }
4056747b715Smrg    return;
40635c4bbdfSmrg err:
4076747b715Smrg    rec->status = rc;
4086747b715Smrg}
4096747b715Smrg
4106747b715Smrgstatic void
41135c4bbdfSmrgSELinuxReceive(CallbackListPtr *pcbl, void *unused, void *calldata)
4126747b715Smrg{
4136747b715Smrg    XaceReceiveAccessRec *rec = calldata;
4146747b715Smrg    SELinuxSubjectRec *subj;
4156747b715Smrg    SELinuxObjectRec *obj, ev_sid;
41635c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = NULL };
4176747b715Smrg    security_class_t class;
4186747b715Smrg    int rc, i, type;
4196747b715Smrg
4206747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
4216747b715Smrg    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
4226747b715Smrg
4236747b715Smrg    /* Check receive permission on window */
4246747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess,
42535c4bbdfSmrg                        &auditdata);
4266747b715Smrg    if (rc != Success)
42735c4bbdfSmrg        goto err;
4286747b715Smrg
4296747b715Smrg    /* Check receive permission on specific event types */
4306747b715Smrg    for (i = 0; i < rec->count; i++) {
43135c4bbdfSmrg        type = rec->events[i].u.u.type;
43235c4bbdfSmrg        class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
4336747b715Smrg
43435c4bbdfSmrg        rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
43535c4bbdfSmrg        if (rc != Success)
43635c4bbdfSmrg            goto err;
4376747b715Smrg
43835c4bbdfSmrg        auditdata.event = type;
43935c4bbdfSmrg        rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata);
44035c4bbdfSmrg        if (rc != Success)
44135c4bbdfSmrg            goto err;
4426747b715Smrg    }
4436747b715Smrg    return;
44435c4bbdfSmrg err:
4456747b715Smrg    rec->status = rc;
4466747b715Smrg}
4476747b715Smrg
4486747b715Smrgstatic void
44935c4bbdfSmrgSELinuxExtension(CallbackListPtr *pcbl, void *unused, void *calldata)
4506747b715Smrg{
4516747b715Smrg    XaceExtAccessRec *rec = calldata;
4526747b715Smrg    SELinuxSubjectRec *subj, *serv;
4536747b715Smrg    SELinuxObjectRec *obj;
45435c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client };
4556747b715Smrg    int rc;
4566747b715Smrg
4576747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
4586747b715Smrg    obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey);
4596747b715Smrg
4606747b715Smrg    /* If this is a new object that needs labeling, do it now */
4616747b715Smrg    /* XXX there should be a separate callback for this */
4626747b715Smrg    if (obj->sid == NULL) {
46335c4bbdfSmrg        security_id_t sid;
46435c4bbdfSmrg
46535c4bbdfSmrg        serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
46635c4bbdfSmrg        rc = SELinuxExtensionToSID(rec->ext->name, &sid);
46735c4bbdfSmrg        if (rc != Success) {
46835c4bbdfSmrg            rec->status = rc;
46935c4bbdfSmrg            return;
47035c4bbdfSmrg        }
47135c4bbdfSmrg
47235c4bbdfSmrg        /* Perform a transition to obtain the final SID */
47335c4bbdfSmrg        if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
47435c4bbdfSmrg                               &obj->sid) < 0) {
47535c4bbdfSmrg            ErrorF("SELinux: a SID transition call failed!\n");
47635c4bbdfSmrg            rec->status = BadValue;
47735c4bbdfSmrg            return;
47835c4bbdfSmrg        }
4796747b715Smrg    }
4806747b715Smrg
4816747b715Smrg    /* Perform the security check */
48235c4bbdfSmrg    auditdata.extension = (char *) rec->ext->name;
4836747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode,
48435c4bbdfSmrg                        &auditdata);
4856747b715Smrg    if (rc != Success)
48635c4bbdfSmrg        rec->status = rc;
4876747b715Smrg}
4886747b715Smrg
4896747b715Smrgstatic void
49035c4bbdfSmrgSELinuxSelection(CallbackListPtr *pcbl, void *unused, void *calldata)
4916747b715Smrg{
4926747b715Smrg    XaceSelectionAccessRec *rec = calldata;
4936747b715Smrg    SELinuxSubjectRec *subj;
4946747b715Smrg    SELinuxObjectRec *obj, *data;
4956747b715Smrg    Selection *pSel = *rec->ppSel;
4966747b715Smrg    Atom name = pSel->selection;
4976747b715Smrg    Mask access_mode = rec->access_mode;
49835c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client,.selection = name };
4996747b715Smrg    security_id_t tsid;
5006747b715Smrg    int rc;
5016747b715Smrg
5026747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
5036747b715Smrg    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
5046747b715Smrg
5056747b715Smrg    /* If this is a new object that needs labeling, do it now */
5066747b715Smrg    if (access_mode & DixCreateAccess) {
50735c4bbdfSmrg        rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly);
50835c4bbdfSmrg        if (rc != Success)
50935c4bbdfSmrg            obj->sid = unlabeled_sid;
51035c4bbdfSmrg        access_mode = DixSetAttrAccess;
5116747b715Smrg    }
5126747b715Smrg    /* If this is a polyinstantiated object, find the right instance */
5136747b715Smrg    else if (obj->poly) {
51435c4bbdfSmrg        rc = SELinuxSelectionToSID(name, subj, &tsid, NULL);
51535c4bbdfSmrg        if (rc != Success) {
51635c4bbdfSmrg            rec->status = rc;
51735c4bbdfSmrg            return;
51835c4bbdfSmrg        }
51935c4bbdfSmrg        while (pSel->selection != name || obj->sid != tsid) {
52035c4bbdfSmrg            if ((pSel = pSel->next) == NULL)
52135c4bbdfSmrg                break;
52235c4bbdfSmrg            obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
52335c4bbdfSmrg        }
52435c4bbdfSmrg
52535c4bbdfSmrg        if (pSel)
52635c4bbdfSmrg            *rec->ppSel = pSel;
52735c4bbdfSmrg        else {
52835c4bbdfSmrg            rec->status = BadMatch;
52935c4bbdfSmrg            return;
53035c4bbdfSmrg        }
5316747b715Smrg    }
5326747b715Smrg
5336747b715Smrg    /* Perform the security check */
5346747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode,
53535c4bbdfSmrg                        &auditdata);
5366747b715Smrg    if (rc != Success)
53735c4bbdfSmrg        rec->status = rc;
5386747b715Smrg
5396747b715Smrg    /* Label the content (advisory only) */
5406747b715Smrg    if (access_mode & DixSetAttrAccess) {
54135c4bbdfSmrg        data = dixLookupPrivate(&pSel->devPrivates, dataKey);
54235c4bbdfSmrg        if (subj->sel_create_sid)
54335c4bbdfSmrg            data->sid = subj->sel_create_sid;
54435c4bbdfSmrg        else
54535c4bbdfSmrg            data->sid = obj->sid;
5466747b715Smrg    }
5476747b715Smrg}
5486747b715Smrg
5496747b715Smrgstatic void
55035c4bbdfSmrgSELinuxProperty(CallbackListPtr *pcbl, void *unused, void *calldata)
5516747b715Smrg{
5526747b715Smrg    XacePropertyAccessRec *rec = calldata;
5536747b715Smrg    SELinuxSubjectRec *subj;
5546747b715Smrg    SELinuxObjectRec *obj, *data;
5556747b715Smrg    PropertyPtr pProp = *rec->ppProp;
5566747b715Smrg    Atom name = pProp->propertyName;
55735c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client,.property = name };
5586747b715Smrg    security_id_t tsid;
5596747b715Smrg    int rc;
5606747b715Smrg
5616747b715Smrg    /* Don't care about the new content check */
5626747b715Smrg    if (rec->access_mode & DixPostAccess)
56335c4bbdfSmrg        return;
5646747b715Smrg
5656747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
5666747b715Smrg    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
5676747b715Smrg
5686747b715Smrg    /* If this is a new object that needs labeling, do it now */
5696747b715Smrg    if (rec->access_mode & DixCreateAccess) {
57035c4bbdfSmrg        rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly);
57135c4bbdfSmrg        if (rc != Success) {
57235c4bbdfSmrg            rec->status = rc;
57335c4bbdfSmrg            return;
57435c4bbdfSmrg        }
5756747b715Smrg    }
5766747b715Smrg    /* If this is a polyinstantiated object, find the right instance */
5776747b715Smrg    else if (obj->poly) {
57835c4bbdfSmrg        rc = SELinuxPropertyToSID(name, subj, &tsid, NULL);
57935c4bbdfSmrg        if (rc != Success) {
58035c4bbdfSmrg            rec->status = rc;
58135c4bbdfSmrg            return;
58235c4bbdfSmrg        }
58335c4bbdfSmrg        while (pProp->propertyName != name || obj->sid != tsid) {
58435c4bbdfSmrg            if ((pProp = pProp->next) == NULL)
58535c4bbdfSmrg                break;
58635c4bbdfSmrg            obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
58735c4bbdfSmrg        }
58835c4bbdfSmrg
58935c4bbdfSmrg        if (pProp)
59035c4bbdfSmrg            *rec->ppProp = pProp;
59135c4bbdfSmrg        else {
59235c4bbdfSmrg            rec->status = BadMatch;
59335c4bbdfSmrg            return;
59435c4bbdfSmrg        }
5956747b715Smrg    }
5966747b715Smrg
5976747b715Smrg    /* Perform the security check */
5986747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode,
59935c4bbdfSmrg                        &auditdata);
6006747b715Smrg    if (rc != Success)
60135c4bbdfSmrg        rec->status = rc;
6026747b715Smrg
6036747b715Smrg    /* Label the content (advisory only) */
6046747b715Smrg    if (rec->access_mode & DixWriteAccess) {
60535c4bbdfSmrg        data = dixLookupPrivate(&pProp->devPrivates, dataKey);
60635c4bbdfSmrg        if (subj->prp_create_sid)
60735c4bbdfSmrg            data->sid = subj->prp_create_sid;
60835c4bbdfSmrg        else
60935c4bbdfSmrg            data->sid = obj->sid;
6106747b715Smrg    }
6116747b715Smrg}
6126747b715Smrg
6136747b715Smrgstatic void
61435c4bbdfSmrgSELinuxResource(CallbackListPtr *pcbl, void *unused, void *calldata)
6156747b715Smrg{
6166747b715Smrg    XaceResourceAccessRec *rec = calldata;
6176747b715Smrg    SELinuxSubjectRec *subj;
6186747b715Smrg    SELinuxObjectRec *obj;
61935c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client };
6206747b715Smrg    Mask access_mode = rec->access_mode;
6216747b715Smrg    PrivateRec **privatePtr;
6226747b715Smrg    security_class_t class;
6236747b715Smrg    int rc, offset;
6246747b715Smrg
6256747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
6266747b715Smrg
6276747b715Smrg    /* Determine if the resource object has a devPrivates field */
6286747b715Smrg    offset = dixLookupPrivateOffset(rec->rtype);
6296747b715Smrg    if (offset < 0) {
63035c4bbdfSmrg        /* No: use the SID of the owning client */
63135c4bbdfSmrg        class = SECCLASS_X_RESOURCE;
63235c4bbdfSmrg        privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
63335c4bbdfSmrg        obj = dixLookupPrivate(privatePtr, objectKey);
63435c4bbdfSmrg    }
63535c4bbdfSmrg    else {
63635c4bbdfSmrg        /* Yes: use the SID from the resource object itself */
63735c4bbdfSmrg        class = SELinuxTypeToClass(rec->rtype);
63835c4bbdfSmrg        privatePtr = DEVPRIV_AT(rec->res, offset);
63935c4bbdfSmrg        obj = dixLookupPrivate(privatePtr, objectKey);
6406747b715Smrg    }
6416747b715Smrg
6426747b715Smrg    /* If this is a new object that needs labeling, do it now */
6436747b715Smrg    if (access_mode & DixCreateAccess && offset >= 0) {
64435c4bbdfSmrg        rc = SELinuxLabelResource(rec, subj, obj, class);
64535c4bbdfSmrg        if (rc != Success) {
64635c4bbdfSmrg            rec->status = rc;
64735c4bbdfSmrg            return;
64835c4bbdfSmrg        }
6496747b715Smrg    }
6506747b715Smrg
6516747b715Smrg    /* Collapse generic resource permissions down to read/write */
6526747b715Smrg    if (class == SECCLASS_X_RESOURCE) {
65335c4bbdfSmrg        access_mode = ! !(rec->access_mode & SELinuxReadMask);  /* rd */
65435c4bbdfSmrg        access_mode |= ! !(rec->access_mode & ~SELinuxReadMask) << 1;   /* wr */
6556747b715Smrg    }
6566747b715Smrg
6576747b715Smrg    /* Perform the security check */
6586747b715Smrg    auditdata.restype = rec->rtype;
6596747b715Smrg    auditdata.id = rec->id;
6606747b715Smrg    rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata);
6616747b715Smrg    if (rc != Success)
66235c4bbdfSmrg        rec->status = rc;
6636747b715Smrg
6646747b715Smrg    /* Perform the background none check on windows */
6656747b715Smrg    if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) {
66635c4bbdfSmrg        rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata);
66735c4bbdfSmrg        if (rc != Success)
66835c4bbdfSmrg            ((WindowPtr) rec->res)->forcedBG = TRUE;
6696747b715Smrg    }
6706747b715Smrg}
6716747b715Smrg
6726747b715Smrgstatic void
67335c4bbdfSmrgSELinuxScreen(CallbackListPtr *pcbl, void *is_saver, void *calldata)
6746747b715Smrg{
6756747b715Smrg    XaceScreenAccessRec *rec = calldata;
6766747b715Smrg    SELinuxSubjectRec *subj;
6776747b715Smrg    SELinuxObjectRec *obj;
67835c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client };
6796747b715Smrg    Mask access_mode = rec->access_mode;
6806747b715Smrg    int rc;
6816747b715Smrg
6826747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
6836747b715Smrg    obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey);
6846747b715Smrg
6856747b715Smrg    /* If this is a new object that needs labeling, do it now */
6866747b715Smrg    if (access_mode & DixCreateAccess) {
68735c4bbdfSmrg        /* Perform a transition to obtain the final SID */
68835c4bbdfSmrg        if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
68935c4bbdfSmrg                               &obj->sid) < 0) {
69035c4bbdfSmrg            ErrorF("SELinux: a compute_create call failed!\n");
69135c4bbdfSmrg            rec->status = BadValue;
69235c4bbdfSmrg            return;
69335c4bbdfSmrg        }
6946747b715Smrg    }
6956747b715Smrg
6966747b715Smrg    if (is_saver)
69735c4bbdfSmrg        access_mode <<= 2;
6986747b715Smrg
6996747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata);
7006747b715Smrg    if (rc != Success)
70135c4bbdfSmrg        rec->status = rc;
7026747b715Smrg}
7036747b715Smrg
7046747b715Smrgstatic void
70535c4bbdfSmrgSELinuxClient(CallbackListPtr *pcbl, void *unused, void *calldata)
7066747b715Smrg{
7076747b715Smrg    XaceClientAccessRec *rec = calldata;
7086747b715Smrg    SELinuxSubjectRec *subj;
7096747b715Smrg    SELinuxObjectRec *obj;
71035c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client };
7116747b715Smrg    int rc;
7126747b715Smrg
7136747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
7146747b715Smrg    obj = dixLookupPrivate(&rec->target->devPrivates, objectKey);
7156747b715Smrg
7166747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode,
71735c4bbdfSmrg                        &auditdata);
7186747b715Smrg    if (rc != Success)
71935c4bbdfSmrg        rec->status = rc;
7206747b715Smrg}
7216747b715Smrg
7226747b715Smrgstatic void
72335c4bbdfSmrgSELinuxServer(CallbackListPtr *pcbl, void *unused, void *calldata)
7246747b715Smrg{
7256747b715Smrg    XaceServerAccessRec *rec = calldata;
7266747b715Smrg    SELinuxSubjectRec *subj;
7276747b715Smrg    SELinuxObjectRec *obj;
72835c4bbdfSmrg    SELinuxAuditRec auditdata = {.client = rec->client };
7296747b715Smrg    int rc;
7306747b715Smrg
7316747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
7326747b715Smrg    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
7336747b715Smrg
7346747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode,
73535c4bbdfSmrg                        &auditdata);
7366747b715Smrg    if (rc != Success)
73735c4bbdfSmrg        rec->status = rc;
7386747b715Smrg}
7396747b715Smrg
7406747b715Smrg/*
7416747b715Smrg * DIX Callbacks
7426747b715Smrg */
7436747b715Smrg
7446747b715Smrgstatic void
74535c4bbdfSmrgSELinuxClientState(CallbackListPtr *pcbl, void *unused, void *calldata)
7466747b715Smrg{
7476747b715Smrg    NewClientInfoRec *pci = calldata;
7486747b715Smrg
7496747b715Smrg    switch (pci->client->clientState) {
7506747b715Smrg    case ClientStateInitial:
75135c4bbdfSmrg        SELinuxLabelClient(pci->client);
75235c4bbdfSmrg        break;
7536747b715Smrg
7546747b715Smrg    default:
75535c4bbdfSmrg        break;
7566747b715Smrg    }
7576747b715Smrg}
7586747b715Smrg
7596747b715Smrgstatic void
76035c4bbdfSmrgSELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
7616747b715Smrg{
7626747b715Smrg    ResourceStateInfoRec *rec = calldata;
7636747b715Smrg    SELinuxSubjectRec *subj;
7646747b715Smrg    SELinuxObjectRec *obj;
7656747b715Smrg    WindowPtr pWin;
7666747b715Smrg
7676747b715Smrg    if (rec->type != RT_WINDOW)
76835c4bbdfSmrg        return;
7696747b715Smrg    if (rec->state != ResourceStateAdding)
77035c4bbdfSmrg        return;
7716747b715Smrg
77235c4bbdfSmrg    pWin = (WindowPtr) rec->value;
7736747b715Smrg    subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
7746747b715Smrg
7756747b715Smrg    if (subj->sid) {
77635c4bbdfSmrg        security_context_t ctx;
77735c4bbdfSmrg        int rc = avc_sid_to_context_raw(subj->sid, &ctx);
77835c4bbdfSmrg
77935c4bbdfSmrg        if (rc < 0)
78035c4bbdfSmrg            FatalError("SELinux: Failed to get security context!\n");
78135c4bbdfSmrg        rc = dixChangeWindowProperty(serverClient,
78235c4bbdfSmrg                                     pWin, atom_client_ctx, XA_STRING, 8,
78335c4bbdfSmrg                                     PropModeReplace, strlen(ctx), ctx, FALSE);
78435c4bbdfSmrg        if (rc != Success)
78535c4bbdfSmrg            FatalError("SELinux: Failed to set label property on window!\n");
78635c4bbdfSmrg        freecon(ctx);
78735c4bbdfSmrg    }
78835c4bbdfSmrg    else
78935c4bbdfSmrg        FatalError("SELinux: Unexpected unlabeled client found\n");
7906747b715Smrg
7916747b715Smrg    obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
7926747b715Smrg
7936747b715Smrg    if (obj->sid) {
79435c4bbdfSmrg        security_context_t ctx;
79535c4bbdfSmrg        int rc = avc_sid_to_context_raw(obj->sid, &ctx);
79635c4bbdfSmrg
79735c4bbdfSmrg        if (rc < 0)
79835c4bbdfSmrg            FatalError("SELinux: Failed to get security context!\n");
79935c4bbdfSmrg        rc = dixChangeWindowProperty(serverClient,
80035c4bbdfSmrg                                     pWin, atom_ctx, XA_STRING, 8,
80135c4bbdfSmrg                                     PropModeReplace, strlen(ctx), ctx, FALSE);
80235c4bbdfSmrg        if (rc != Success)
80335c4bbdfSmrg            FatalError("SELinux: Failed to set label property on window!\n");
80435c4bbdfSmrg        freecon(ctx);
80535c4bbdfSmrg    }
80635c4bbdfSmrg    else
80735c4bbdfSmrg        FatalError("SELinux: Unexpected unlabeled window found\n");
8086747b715Smrg}
8096747b715Smrg
8106747b715Smrgstatic int netlink_fd;
8116747b715Smrg
8126747b715Smrgstatic void
8131b5d61b8SmrgSELinuxNetlinkNotify(int fd, int ready, void *data)
8146747b715Smrg{
8151b5d61b8Smrg    avc_netlink_check_nb();
8166747b715Smrg}
8176747b715Smrg
8186747b715Smrgvoid
8196747b715SmrgSELinuxFlaskReset(void)
8206747b715Smrg{
8216747b715Smrg    /* Unregister callbacks */
8226747b715Smrg    DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL);
8236747b715Smrg    DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
8246747b715Smrg
8256747b715Smrg    XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
8266747b715Smrg    XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
8276747b715Smrg    XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
8286747b715Smrg    XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
8296747b715Smrg    XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
8306747b715Smrg    XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
8316747b715Smrg    XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
8326747b715Smrg    XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
8336747b715Smrg    XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
8346747b715Smrg    XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
8356747b715Smrg    XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
8366747b715Smrg    XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
8376747b715Smrg
8386747b715Smrg    /* Tear down SELinux stuff */
8396747b715Smrg    audit_close(audit_fd);
8406747b715Smrg    avc_netlink_release_fd();
8411b5d61b8Smrg    RemoveNotifyFd(netlink_fd);
8426747b715Smrg
8436747b715Smrg    avc_destroy();
8446747b715Smrg}
8456747b715Smrg
8466747b715Smrgvoid
8476747b715SmrgSELinuxFlaskInit(void)
8486747b715Smrg{
84935c4bbdfSmrg    struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *) 0 };
8506747b715Smrg    security_context_t ctx;
8516747b715Smrg    int ret = TRUE;
8526747b715Smrg
85335c4bbdfSmrg    switch (selinuxEnforcingState) {
8546747b715Smrg    case SELINUX_MODE_ENFORCING:
85535c4bbdfSmrg        LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n");
85635c4bbdfSmrg        avc_option.value = (char *) 1;
85735c4bbdfSmrg        break;
8586747b715Smrg    case SELINUX_MODE_PERMISSIVE:
85935c4bbdfSmrg        LogMessage(X_INFO, "SELinux: Configured in permissive mode\n");
86035c4bbdfSmrg        avc_option.value = (char *) 0;
86135c4bbdfSmrg        break;
8626747b715Smrg    default:
86335c4bbdfSmrg        avc_option.type = AVC_OPT_UNUSED;
86435c4bbdfSmrg        break;
8656747b715Smrg    }
8666747b715Smrg
8676747b715Smrg    /* Set up SELinux stuff */
86835c4bbdfSmrg    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) SELinuxLog);
86935c4bbdfSmrg    selinux_set_callback(SELINUX_CB_AUDIT,
87035c4bbdfSmrg                         (union selinux_callback) SELinuxAudit);
8716747b715Smrg
8726747b715Smrg    if (selinux_set_mapping(map) < 0) {
87335c4bbdfSmrg        if (errno == EINVAL) {
87435c4bbdfSmrg            ErrorF
87535c4bbdfSmrg                ("SELinux: Invalid object class mapping, disabling SELinux support.\n");
87635c4bbdfSmrg            return;
87735c4bbdfSmrg        }
87835c4bbdfSmrg        FatalError("SELinux: Failed to set up security class mapping\n");
8796747b715Smrg    }
8806747b715Smrg
8816747b715Smrg    if (avc_open(&avc_option, 1) < 0)
88235c4bbdfSmrg        FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n");
8836747b715Smrg
8846747b715Smrg    if (security_get_initial_context_raw("unlabeled", &ctx) < 0)
88535c4bbdfSmrg        FatalError("SELinux: Failed to look up unlabeled context\n");
8866747b715Smrg    if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0)
88735c4bbdfSmrg        FatalError("SELinux: a context_to_SID call failed!\n");
8886747b715Smrg    freecon(ctx);
8896747b715Smrg
8906747b715Smrg    /* Prepare for auditing */
8916747b715Smrg    audit_fd = audit_open();
8926747b715Smrg    if (audit_fd < 0)
89335c4bbdfSmrg        FatalError("SELinux: Failed to open the system audit log\n");
8946747b715Smrg
8956747b715Smrg    /* Allocate private storage */
89635c4bbdfSmrg    if (!dixRegisterPrivateKey
89735c4bbdfSmrg        (subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) ||
89835c4bbdfSmrg        !dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX,
89935c4bbdfSmrg                               sizeof(SELinuxObjectRec)) ||
90035c4bbdfSmrg        !dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX,
90135c4bbdfSmrg                               sizeof(SELinuxObjectRec)))
90235c4bbdfSmrg        FatalError("SELinux: Failed to allocate private storage.\n");
9036747b715Smrg
9046747b715Smrg    /* Create atoms for doing window labeling */
9056747b715Smrg    atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
9066747b715Smrg    if (atom_ctx == BAD_RESOURCE)
90735c4bbdfSmrg        FatalError("SELinux: Failed to create atom\n");
9086747b715Smrg    atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
9096747b715Smrg    if (atom_client_ctx == BAD_RESOURCE)
91035c4bbdfSmrg        FatalError("SELinux: Failed to create atom\n");
9116747b715Smrg
9126747b715Smrg    netlink_fd = avc_netlink_acquire_fd();
9131b5d61b8Smrg    SetNotifyFd(netlink_fd, SELinuxNetlinkNotify, X_NOTIFY_READ, NULL);
9146747b715Smrg
9156747b715Smrg    /* Register callbacks */
9166747b715Smrg    ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
9176747b715Smrg    ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
9186747b715Smrg
9196747b715Smrg    ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
9206747b715Smrg    ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
9216747b715Smrg    ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
9226747b715Smrg    ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
9236747b715Smrg    ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
9246747b715Smrg    ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
9256747b715Smrg    ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
9266747b715Smrg    ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
9276747b715Smrg    ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
9286747b715Smrg    ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
9296747b715Smrg    ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
9306747b715Smrg    ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
9316747b715Smrg    if (!ret)
93235c4bbdfSmrg        FatalError("SELinux: Failed to register one or more callbacks\n");
9336747b715Smrg
9346747b715Smrg    /* Label objects that were created before we could register ourself */
9356747b715Smrg    SELinuxLabelInitial();
9366747b715Smrg}
937