xselinux_hooks.c revision 6747b715
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"
436747b715Smrg#include "../os/osdep.h"
446747b715Smrg#define _XSELINUX_NEED_FLASK_MAP
456747b715Smrg#include "xselinuxint.h"
466747b715Smrg
476747b715Smrg
486747b715Smrg/* structure passed to auditing callback */
496747b715Smrgtypedef struct {
506747b715Smrg    ClientPtr client;	/* client */
516747b715Smrg    DeviceIntPtr dev;	/* device */
526747b715Smrg    char *command;	/* client's executable path */
536747b715Smrg    unsigned id;	/* resource id, if any */
546747b715Smrg    int restype;	/* resource type, if any */
556747b715Smrg    int event;		/* event type, if any */
566747b715Smrg    Atom property;	/* property name, if any */
576747b715Smrg    Atom selection;	/* selection name, if any */
586747b715Smrg    char *extension;	/* extension name, if any */
596747b715Smrg} SELinuxAuditRec;
606747b715Smrg
616747b715Smrg/* private state keys */
626747b715SmrgDevPrivateKeyRec subjectKeyRec;
636747b715SmrgDevPrivateKeyRec objectKeyRec;
646747b715SmrgDevPrivateKeyRec dataKeyRec;
656747b715Smrg
666747b715Smrg/* audit file descriptor */
676747b715Smrgstatic int audit_fd;
686747b715Smrg
696747b715Smrg/* atoms for window label properties */
706747b715Smrgstatic Atom atom_ctx;
716747b715Smrgstatic Atom atom_client_ctx;
726747b715Smrg
736747b715Smrg/* The unlabeled SID */
746747b715Smrgstatic security_id_t unlabeled_sid;
756747b715Smrg
766747b715Smrg/* forward declarations */
776747b715Smrgstatic void SELinuxScreen(CallbackListPtr *, pointer, pointer);
786747b715Smrg
796747b715Smrg/* "true" pointer value for use as callback data */
806747b715Smrgstatic pointer truep = (pointer)1;
816747b715Smrg
826747b715Smrg
836747b715Smrg/*
846747b715Smrg * Performs an SELinux permission check.
856747b715Smrg */
866747b715Smrgstatic int
876747b715SmrgSELinuxDoCheck(SELinuxSubjectRec *subj, SELinuxObjectRec *obj,
886747b715Smrg	       security_class_t class, Mask mode, SELinuxAuditRec *auditdata)
896747b715Smrg{
906747b715Smrg    /* serverClient requests OK */
916747b715Smrg    if (subj->privileged)
926747b715Smrg	return Success;
936747b715Smrg
946747b715Smrg    auditdata->command = subj->command;
956747b715Smrg    errno = 0;
966747b715Smrg
976747b715Smrg    if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref,
986747b715Smrg		     auditdata) < 0) {
996747b715Smrg	if (mode == DixUnknownAccess)
1006747b715Smrg	    return Success; /* DixUnknownAccess requests OK ... for now */
1016747b715Smrg	if (errno == EACCES)
1026747b715Smrg	    return BadAccess;
1036747b715Smrg	ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno);
1046747b715Smrg	return BadValue;
1056747b715Smrg    }
1066747b715Smrg
1076747b715Smrg    return Success;
1086747b715Smrg}
1096747b715Smrg
1106747b715Smrg/*
1116747b715Smrg * Labels a newly connected client.
1126747b715Smrg */
1136747b715Smrgstatic void
1146747b715SmrgSELinuxLabelClient(ClientPtr client)
1156747b715Smrg{
1166747b715Smrg    int fd = XaceGetConnectionNumber(client);
1176747b715Smrg    SELinuxSubjectRec *subj;
1186747b715Smrg    SELinuxObjectRec *obj;
1196747b715Smrg    security_context_t ctx;
1206747b715Smrg
1216747b715Smrg    subj = dixLookupPrivate(&client->devPrivates, subjectKey);
1226747b715Smrg    obj = dixLookupPrivate(&client->devPrivates, objectKey);
1236747b715Smrg
1246747b715Smrg    /* Try to get a context from the socket */
1256747b715Smrg    if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) {
1266747b715Smrg	/* Otherwise, fall back to a default context */
1276747b715Smrg	ctx = SELinuxDefaultClientLabel();
1286747b715Smrg    }
1296747b715Smrg
1306747b715Smrg    /* For local clients, try and determine the executable name */
1316747b715Smrg    if (XaceIsLocal(client)) {
1326747b715Smrg	struct ucred creds;
1336747b715Smrg	socklen_t len = sizeof(creds);
1346747b715Smrg	char path[PATH_MAX + 1];
1356747b715Smrg	size_t bytes;
1366747b715Smrg
1376747b715Smrg	memset(&creds, 0, sizeof(creds));
1386747b715Smrg	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0)
1396747b715Smrg	    goto finish;
1406747b715Smrg
1416747b715Smrg	snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid);
1426747b715Smrg	fd = open(path, O_RDONLY);
1436747b715Smrg	if (fd < 0)
1446747b715Smrg	    goto finish;
1456747b715Smrg
1466747b715Smrg	bytes = read(fd, path, PATH_MAX + 1);
1476747b715Smrg	close(fd);
1486747b715Smrg	if (bytes <= 0)
1496747b715Smrg	    goto finish;
1506747b715Smrg
1516747b715Smrg	strncpy(subj->command, path, COMMAND_LEN - 1);
1526747b715Smrg    }
1536747b715Smrg
1546747b715Smrgfinish:
1556747b715Smrg    /* Get a SID from the context */
1566747b715Smrg    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
1576747b715Smrg	FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n",
1586747b715Smrg		   client->index, ctx);
1596747b715Smrg
1606747b715Smrg    obj->sid = subj->sid;
1616747b715Smrg    freecon(ctx);
1626747b715Smrg}
1636747b715Smrg
1646747b715Smrg/*
1656747b715Smrg * Labels initial server objects.
1666747b715Smrg */
1676747b715Smrgstatic void
1686747b715SmrgSELinuxLabelInitial(void)
1696747b715Smrg{
1706747b715Smrg    int i;
1716747b715Smrg    XaceScreenAccessRec srec;
1726747b715Smrg    SELinuxSubjectRec *subj;
1736747b715Smrg    SELinuxObjectRec *obj;
1746747b715Smrg    security_context_t ctx;
1756747b715Smrg    pointer unused;
1766747b715Smrg
1776747b715Smrg    /* Do the serverClient */
1786747b715Smrg    subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
1796747b715Smrg    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
1806747b715Smrg    subj->privileged = 1;
1816747b715Smrg
1826747b715Smrg    /* Use the context of the X server process for the serverClient */
1836747b715Smrg    if (getcon_raw(&ctx) < 0)
1846747b715Smrg	FatalError("SELinux: couldn't get context of X server process\n");
1856747b715Smrg
1866747b715Smrg    /* Get a SID from the context */
1876747b715Smrg    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
1886747b715Smrg	FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx);
1896747b715Smrg
1906747b715Smrg    obj->sid = subj->sid;
1916747b715Smrg    freecon(ctx);
1926747b715Smrg
1936747b715Smrg    srec.client = serverClient;
1946747b715Smrg    srec.access_mode = DixCreateAccess;
1956747b715Smrg    srec.status = Success;
1966747b715Smrg
1976747b715Smrg    for (i = 0; i < screenInfo.numScreens; i++) {
1986747b715Smrg	/* Do the screen object */
1996747b715Smrg	srec.screen = screenInfo.screens[i];
2006747b715Smrg	SELinuxScreen(NULL, NULL, &srec);
2016747b715Smrg
2026747b715Smrg	/* Do the default colormap */
2036747b715Smrg	dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap,
2046747b715Smrg			  RT_COLORMAP, serverClient, DixCreateAccess);
2056747b715Smrg    }
2066747b715Smrg}
2076747b715Smrg
2086747b715Smrg/*
2096747b715Smrg * Labels new resource objects.
2106747b715Smrg */
2116747b715Smrgstatic int
2126747b715SmrgSELinuxLabelResource(XaceResourceAccessRec *rec, SELinuxSubjectRec *subj,
2136747b715Smrg		     SELinuxObjectRec *obj, security_class_t class)
2146747b715Smrg{
2156747b715Smrg    int offset;
2166747b715Smrg    security_id_t tsid;
2176747b715Smrg
2186747b715Smrg    /* Check for a create context */
2196747b715Smrg    if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) {
2206747b715Smrg	obj->sid = subj->win_create_sid;
2216747b715Smrg	return Success;
2226747b715Smrg    }
2236747b715Smrg
2246747b715Smrg    if (rec->parent)
2256747b715Smrg	offset = dixLookupPrivateOffset(rec->ptype);
2266747b715Smrg
2276747b715Smrg    if (rec->parent && offset >= 0) {
2286747b715Smrg	/* Use the SID of the parent object in the labeling operation */
2296747b715Smrg	PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset);
2306747b715Smrg	SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey);
2316747b715Smrg	tsid = pobj->sid;
2326747b715Smrg    } else {
2336747b715Smrg	/* Use the SID of the subject */
2346747b715Smrg	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) {
2396747b715Smrg	ErrorF("SELinux: a compute_create call failed!\n");
2406747b715Smrg	return BadValue;
2416747b715Smrg    }
2426747b715Smrg
2436747b715Smrg    return Success;
2446747b715Smrg}
2456747b715Smrg
2466747b715Smrg
2476747b715Smrg/*
2486747b715Smrg * Libselinux Callbacks
2496747b715Smrg */
2506747b715Smrg
2516747b715Smrgstatic int
2526747b715SmrgSELinuxAudit(void *auditdata,
2536747b715Smrg	     security_class_t class,
2546747b715Smrg	     char *msgbuf,
2556747b715Smrg	     size_t msgbufsize)
2566747b715Smrg{
2576747b715Smrg    SELinuxAuditRec *audit = auditdata;
2586747b715Smrg    ClientPtr client = audit->client;
2596747b715Smrg    char idNum[16];
2606747b715Smrg    const char *propertyName, *selectionName;
2616747b715Smrg    int major = -1, minor = -1;
2626747b715Smrg
2636747b715Smrg    if (client) {
2646747b715Smrg	REQUEST(xReq);
2656747b715Smrg	if (stuff) {
2666747b715Smrg	    major = stuff->reqType;
2676747b715Smrg	    minor = MinorOpcodeOfRequest(client);
2686747b715Smrg	}
2696747b715Smrg    }
2706747b715Smrg    if (audit->id)
2716747b715Smrg	snprintf(idNum, 16, "%x", audit->id);
2726747b715Smrg
2736747b715Smrg    propertyName = audit->property ? NameForAtom(audit->property) : NULL;
2746747b715Smrg    selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
2756747b715Smrg
2766747b715Smrg    return snprintf(msgbuf, msgbufsize,
2776747b715Smrg		    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
2786747b715Smrg		    (major >= 0) ? "request=" : "",
2796747b715Smrg		    (major >= 0) ? LookupRequestName(major, minor) : "",
2806747b715Smrg		    audit->command ? " comm=" : "",
2816747b715Smrg		    audit->command ? audit->command : "",
2826747b715Smrg		    audit->dev ? " xdevice=\"" : "",
2836747b715Smrg		    audit->dev ? audit->dev->name : "",
2846747b715Smrg		    audit->dev ? "\"" : "",
2856747b715Smrg		    audit->id ? " resid=" : "",
2866747b715Smrg		    audit->id ? idNum : "",
2876747b715Smrg		    audit->restype ? " restype=" : "",
2886747b715Smrg		    audit->restype ? LookupResourceName(audit->restype) : "",
2896747b715Smrg		    audit->event ? " event=" : "",
2906747b715Smrg		    audit->event ? LookupEventName(audit->event & 127) : "",
2916747b715Smrg		    audit->property ? " property=" : "",
2926747b715Smrg		    audit->property ? propertyName : "",
2936747b715Smrg		    audit->selection ? " selection=" : "",
2946747b715Smrg		    audit->selection ? selectionName : "",
2956747b715Smrg		    audit->extension ? " extension=" : "",
2966747b715Smrg		    audit->extension ? audit->extension : "");
2976747b715Smrg}
2986747b715Smrg
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:
3086747b715Smrg	aut = AUDIT_USER_MAC_POLICY_LOAD;
3096747b715Smrg	break;
3106747b715Smrg    case SELINUX_AVC:
3116747b715Smrg	aut = AUDIT_USER_AVC;
3126747b715Smrg	break;
3136747b715Smrg    default:
3146747b715Smrg	aut = AUDIT_USER_SELINUX_ERR;
3156747b715Smrg	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);
3216747b715Smrg    va_end(ap);
3226747b715Smrg    LogMessageVerb(X_WARNING, 0, "%s", buf);
3236747b715Smrg    return 0;
3246747b715Smrg}
3256747b715Smrg
3266747b715Smrg/*
3276747b715Smrg * XACE Callbacks
3286747b715Smrg */
3296747b715Smrg
3306747b715Smrgstatic void
3316747b715SmrgSELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata)
3326747b715Smrg{
3336747b715Smrg    XaceDeviceAccessRec *rec = calldata;
3346747b715Smrg    SELinuxSubjectRec *subj;
3356747b715Smrg    SELinuxObjectRec *obj;
3366747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev };
3376747b715Smrg    security_class_t cls;
3386747b715Smrg    int rc;
3396747b715Smrg
3406747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
3416747b715Smrg    obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey);
3426747b715Smrg
3436747b715Smrg    /* If this is a new object that needs labeling, do it now */
3446747b715Smrg    if (rec->access_mode & DixCreateAccess) {
3456747b715Smrg	SELinuxSubjectRec *dsubj;
3466747b715Smrg	dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
3476747b715Smrg
3486747b715Smrg	if (subj->dev_create_sid) {
3496747b715Smrg	    /* Label the device with the create context */
3506747b715Smrg	    obj->sid = subj->dev_create_sid;
3516747b715Smrg	    dsubj->sid = subj->dev_create_sid;
3526747b715Smrg	} else {
3536747b715Smrg	    /* Label the device directly with the process SID */
3546747b715Smrg	    obj->sid = subj->sid;
3556747b715Smrg	    dsubj->sid = subj->sid;
3566747b715Smrg	}
3576747b715Smrg    }
3586747b715Smrg
3596747b715Smrg    cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD;
3606747b715Smrg    rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata);
3616747b715Smrg    if (rc != Success)
3626747b715Smrg	rec->status = rc;
3636747b715Smrg}
3646747b715Smrg
3656747b715Smrgstatic void
3666747b715SmrgSELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata)
3676747b715Smrg{
3686747b715Smrg    XaceSendAccessRec *rec = calldata;
3696747b715Smrg    SELinuxSubjectRec *subj;
3706747b715Smrg    SELinuxObjectRec *obj, ev_sid;
3716747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev };
3726747b715Smrg    security_class_t class;
3736747b715Smrg    int rc, i, type;
3746747b715Smrg
3756747b715Smrg    if (rec->dev)
3766747b715Smrg	subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
3776747b715Smrg    else
3786747b715Smrg	subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
3796747b715Smrg
3806747b715Smrg    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
3816747b715Smrg
3826747b715Smrg    /* Check send permission on window */
3836747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess,
3846747b715Smrg			&auditdata);
3856747b715Smrg    if (rc != Success)
3866747b715Smrg	goto err;
3876747b715Smrg
3886747b715Smrg    /* Check send permission on specific event types */
3896747b715Smrg    for (i = 0; i < rec->count; i++) {
3906747b715Smrg	type = rec->events[i].u.u.type;
3916747b715Smrg	class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
3926747b715Smrg
3936747b715Smrg	rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
3946747b715Smrg	if (rc != Success)
3956747b715Smrg	    goto err;
3966747b715Smrg
3976747b715Smrg	auditdata.event = type;
3986747b715Smrg	rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata);
3996747b715Smrg	if (rc != Success)
4006747b715Smrg	    goto err;
4016747b715Smrg    }
4026747b715Smrg    return;
4036747b715Smrgerr:
4046747b715Smrg    rec->status = rc;
4056747b715Smrg}
4066747b715Smrg
4076747b715Smrgstatic void
4086747b715SmrgSELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata)
4096747b715Smrg{
4106747b715Smrg    XaceReceiveAccessRec *rec = calldata;
4116747b715Smrg    SELinuxSubjectRec *subj;
4126747b715Smrg    SELinuxObjectRec *obj, ev_sid;
4136747b715Smrg    SELinuxAuditRec auditdata = { .client = NULL };
4146747b715Smrg    security_class_t class;
4156747b715Smrg    int rc, i, type;
4166747b715Smrg
4176747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
4186747b715Smrg    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
4196747b715Smrg
4206747b715Smrg    /* Check receive permission on window */
4216747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess,
4226747b715Smrg			&auditdata);
4236747b715Smrg    if (rc != Success)
4246747b715Smrg	goto err;
4256747b715Smrg
4266747b715Smrg    /* Check receive permission on specific event types */
4276747b715Smrg    for (i = 0; i < rec->count; i++) {
4286747b715Smrg	type = rec->events[i].u.u.type;
4296747b715Smrg	class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
4306747b715Smrg
4316747b715Smrg	rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
4326747b715Smrg	if (rc != Success)
4336747b715Smrg	    goto err;
4346747b715Smrg
4356747b715Smrg	auditdata.event = type;
4366747b715Smrg	rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata);
4376747b715Smrg	if (rc != Success)
4386747b715Smrg	    goto err;
4396747b715Smrg    }
4406747b715Smrg    return;
4416747b715Smrgerr:
4426747b715Smrg    rec->status = rc;
4436747b715Smrg}
4446747b715Smrg
4456747b715Smrgstatic void
4466747b715SmrgSELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata)
4476747b715Smrg{
4486747b715Smrg    XaceExtAccessRec *rec = calldata;
4496747b715Smrg    SELinuxSubjectRec *subj, *serv;
4506747b715Smrg    SELinuxObjectRec *obj;
4516747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
4526747b715Smrg    int rc;
4536747b715Smrg
4546747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
4556747b715Smrg    obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey);
4566747b715Smrg
4576747b715Smrg    /* If this is a new object that needs labeling, do it now */
4586747b715Smrg    /* XXX there should be a separate callback for this */
4596747b715Smrg    if (obj->sid == NULL) {
4606747b715Smrg	security_id_t sid;
4616747b715Smrg
4626747b715Smrg	serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
4636747b715Smrg	rc = SELinuxExtensionToSID(rec->ext->name, &sid);
4646747b715Smrg	if (rc != Success) {
4656747b715Smrg	    rec->status = rc;
4666747b715Smrg	    return;
4676747b715Smrg	}
4686747b715Smrg
4696747b715Smrg	/* Perform a transition to obtain the final SID */
4706747b715Smrg	if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
4716747b715Smrg			       &obj->sid) < 0) {
4726747b715Smrg	    ErrorF("SELinux: a SID transition call failed!\n");
4736747b715Smrg	    rec->status = BadValue;
4746747b715Smrg	    return;
4756747b715Smrg	}
4766747b715Smrg    }
4776747b715Smrg
4786747b715Smrg    /* Perform the security check */
4796747b715Smrg    auditdata.extension = rec->ext->name;
4806747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode,
4816747b715Smrg			&auditdata);
4826747b715Smrg    if (rc != Success)
4836747b715Smrg	rec->status = rc;
4846747b715Smrg}
4856747b715Smrg
4866747b715Smrgstatic void
4876747b715SmrgSELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata)
4886747b715Smrg{
4896747b715Smrg    XaceSelectionAccessRec *rec = calldata;
4906747b715Smrg    SELinuxSubjectRec *subj;
4916747b715Smrg    SELinuxObjectRec *obj, *data;
4926747b715Smrg    Selection *pSel = *rec->ppSel;
4936747b715Smrg    Atom name = pSel->selection;
4946747b715Smrg    Mask access_mode = rec->access_mode;
4956747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .selection = name };
4966747b715Smrg    security_id_t tsid;
4976747b715Smrg    int rc;
4986747b715Smrg
4996747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
5006747b715Smrg    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
5016747b715Smrg
5026747b715Smrg    /* If this is a new object that needs labeling, do it now */
5036747b715Smrg    if (access_mode & DixCreateAccess) {
5046747b715Smrg	rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly);
5056747b715Smrg	if (rc != Success)
5066747b715Smrg	    obj->sid = unlabeled_sid;
5076747b715Smrg	access_mode = DixSetAttrAccess;
5086747b715Smrg    }
5096747b715Smrg    /* If this is a polyinstantiated object, find the right instance */
5106747b715Smrg    else if (obj->poly) {
5116747b715Smrg	rc = SELinuxSelectionToSID(name, subj, &tsid, NULL);
5126747b715Smrg	if (rc != Success) {
5136747b715Smrg	    rec->status = rc;
5146747b715Smrg	    return;
5156747b715Smrg	}
5166747b715Smrg	while (pSel->selection != name || obj->sid != tsid) {
5176747b715Smrg	    if ((pSel = pSel->next) == NULL)
5186747b715Smrg		break;
5196747b715Smrg	    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
5206747b715Smrg	}
5216747b715Smrg
5226747b715Smrg	if (pSel)
5236747b715Smrg	    *rec->ppSel = pSel;
5246747b715Smrg	else {
5256747b715Smrg	    rec->status = BadMatch;
5266747b715Smrg	    return;
5276747b715Smrg	}
5286747b715Smrg    }
5296747b715Smrg
5306747b715Smrg    /* Perform the security check */
5316747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode,
5326747b715Smrg			&auditdata);
5336747b715Smrg    if (rc != Success)
5346747b715Smrg	rec->status = rc;
5356747b715Smrg
5366747b715Smrg    /* Label the content (advisory only) */
5376747b715Smrg    if (access_mode & DixSetAttrAccess) {
5386747b715Smrg	data = dixLookupPrivate(&pSel->devPrivates, dataKey);
5396747b715Smrg	if (subj->sel_create_sid)
5406747b715Smrg	    data->sid = subj->sel_create_sid;
5416747b715Smrg	else
5426747b715Smrg	    data->sid = obj->sid;
5436747b715Smrg    }
5446747b715Smrg}
5456747b715Smrg
5466747b715Smrgstatic void
5476747b715SmrgSELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata)
5486747b715Smrg{
5496747b715Smrg    XacePropertyAccessRec *rec = calldata;
5506747b715Smrg    SELinuxSubjectRec *subj;
5516747b715Smrg    SELinuxObjectRec *obj, *data;
5526747b715Smrg    PropertyPtr pProp = *rec->ppProp;
5536747b715Smrg    Atom name = pProp->propertyName;
5546747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .property = name };
5556747b715Smrg    security_id_t tsid;
5566747b715Smrg    int rc;
5576747b715Smrg
5586747b715Smrg    /* Don't care about the new content check */
5596747b715Smrg    if (rec->access_mode & DixPostAccess)
5606747b715Smrg	return;
5616747b715Smrg
5626747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
5636747b715Smrg    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
5646747b715Smrg
5656747b715Smrg    /* If this is a new object that needs labeling, do it now */
5666747b715Smrg    if (rec->access_mode & DixCreateAccess) {
5676747b715Smrg	rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly);
5686747b715Smrg	if (rc != Success) {
5696747b715Smrg	    rec->status = rc;
5706747b715Smrg	    return;
5716747b715Smrg	}
5726747b715Smrg    }
5736747b715Smrg    /* If this is a polyinstantiated object, find the right instance */
5746747b715Smrg    else if (obj->poly) {
5756747b715Smrg	rc = SELinuxPropertyToSID(name, subj, &tsid, NULL);
5766747b715Smrg	if (rc != Success) {
5776747b715Smrg	    rec->status = rc;
5786747b715Smrg	    return;
5796747b715Smrg	}
5806747b715Smrg	while (pProp->propertyName != name || obj->sid != tsid) {
5816747b715Smrg	    if ((pProp = pProp->next) == NULL)
5826747b715Smrg		break;
5836747b715Smrg	    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
5846747b715Smrg	}
5856747b715Smrg
5866747b715Smrg	if (pProp)
5876747b715Smrg	    *rec->ppProp = pProp;
5886747b715Smrg	else {
5896747b715Smrg	    rec->status = BadMatch;
5906747b715Smrg	    return;
5916747b715Smrg	}
5926747b715Smrg    }
5936747b715Smrg
5946747b715Smrg    /* Perform the security check */
5956747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode,
5966747b715Smrg			&auditdata);
5976747b715Smrg    if (rc != Success)
5986747b715Smrg	rec->status = rc;
5996747b715Smrg
6006747b715Smrg    /* Label the content (advisory only) */
6016747b715Smrg    if (rec->access_mode & DixWriteAccess) {
6026747b715Smrg	data = dixLookupPrivate(&pProp->devPrivates, dataKey);
6036747b715Smrg	if (subj->prp_create_sid)
6046747b715Smrg	    data->sid = subj->prp_create_sid;
6056747b715Smrg	else
6066747b715Smrg	    data->sid = obj->sid;
6076747b715Smrg    }
6086747b715Smrg}
6096747b715Smrg
6106747b715Smrgstatic void
6116747b715SmrgSELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata)
6126747b715Smrg{
6136747b715Smrg    XaceResourceAccessRec *rec = calldata;
6146747b715Smrg    SELinuxSubjectRec *subj;
6156747b715Smrg    SELinuxObjectRec *obj;
6166747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
6176747b715Smrg    Mask access_mode = rec->access_mode;
6186747b715Smrg    PrivateRec **privatePtr;
6196747b715Smrg    security_class_t class;
6206747b715Smrg    int rc, offset;
6216747b715Smrg
6226747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
6236747b715Smrg
6246747b715Smrg    /* Determine if the resource object has a devPrivates field */
6256747b715Smrg    offset = dixLookupPrivateOffset(rec->rtype);
6266747b715Smrg    if (offset < 0) {
6276747b715Smrg	/* No: use the SID of the owning client */
6286747b715Smrg	class = SECCLASS_X_RESOURCE;
6296747b715Smrg	privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
6306747b715Smrg	obj = dixLookupPrivate(privatePtr, objectKey);
6316747b715Smrg    } else {
6326747b715Smrg	/* Yes: use the SID from the resource object itself */
6336747b715Smrg	class = SELinuxTypeToClass(rec->rtype);
6346747b715Smrg	privatePtr = DEVPRIV_AT(rec->res, offset);
6356747b715Smrg	obj = dixLookupPrivate(privatePtr, objectKey);
6366747b715Smrg    }
6376747b715Smrg
6386747b715Smrg    /* If this is a new object that needs labeling, do it now */
6396747b715Smrg    if (access_mode & DixCreateAccess && offset >= 0) {
6406747b715Smrg	rc = SELinuxLabelResource(rec, subj, obj, class);
6416747b715Smrg	if (rc != Success) {
6426747b715Smrg	    rec->status = rc;
6436747b715Smrg	    return;
6446747b715Smrg	}
6456747b715Smrg    }
6466747b715Smrg
6476747b715Smrg    /* Collapse generic resource permissions down to read/write */
6486747b715Smrg    if (class == SECCLASS_X_RESOURCE) {
6496747b715Smrg	access_mode = !!(rec->access_mode & SELinuxReadMask); /* rd */
6506747b715Smrg	access_mode |= !!(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */
6516747b715Smrg    }
6526747b715Smrg
6536747b715Smrg    /* Perform the security check */
6546747b715Smrg    auditdata.restype = rec->rtype;
6556747b715Smrg    auditdata.id = rec->id;
6566747b715Smrg    rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata);
6576747b715Smrg    if (rc != Success)
6586747b715Smrg	rec->status = rc;
6596747b715Smrg
6606747b715Smrg    /* Perform the background none check on windows */
6616747b715Smrg    if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) {
6626747b715Smrg	rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata);
6636747b715Smrg	if (rc != Success)
6646747b715Smrg	    ((WindowPtr)rec->res)->forcedBG = TRUE;
6656747b715Smrg    }
6666747b715Smrg}
6676747b715Smrg
6686747b715Smrgstatic void
6696747b715SmrgSELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata)
6706747b715Smrg{
6716747b715Smrg    XaceScreenAccessRec *rec = calldata;
6726747b715Smrg    SELinuxSubjectRec *subj;
6736747b715Smrg    SELinuxObjectRec *obj;
6746747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
6756747b715Smrg    Mask access_mode = rec->access_mode;
6766747b715Smrg    int rc;
6776747b715Smrg
6786747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
6796747b715Smrg    obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey);
6806747b715Smrg
6816747b715Smrg    /* If this is a new object that needs labeling, do it now */
6826747b715Smrg    if (access_mode & DixCreateAccess) {
6836747b715Smrg	/* Perform a transition to obtain the final SID */
6846747b715Smrg	if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
6856747b715Smrg			       &obj->sid) < 0) {
6866747b715Smrg	    ErrorF("SELinux: a compute_create call failed!\n");
6876747b715Smrg	    rec->status = BadValue;
6886747b715Smrg	    return;
6896747b715Smrg	}
6906747b715Smrg    }
6916747b715Smrg
6926747b715Smrg    if (is_saver)
6936747b715Smrg	access_mode <<= 2;
6946747b715Smrg
6956747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata);
6966747b715Smrg    if (rc != Success)
6976747b715Smrg	rec->status = rc;
6986747b715Smrg}
6996747b715Smrg
7006747b715Smrgstatic void
7016747b715SmrgSELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata)
7026747b715Smrg{
7036747b715Smrg    XaceClientAccessRec *rec = calldata;
7046747b715Smrg    SELinuxSubjectRec *subj;
7056747b715Smrg    SELinuxObjectRec *obj;
7066747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
7076747b715Smrg    int rc;
7086747b715Smrg
7096747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
7106747b715Smrg    obj = dixLookupPrivate(&rec->target->devPrivates, objectKey);
7116747b715Smrg
7126747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode,
7136747b715Smrg			&auditdata);
7146747b715Smrg    if (rc != Success)
7156747b715Smrg	rec->status = rc;
7166747b715Smrg}
7176747b715Smrg
7186747b715Smrgstatic void
7196747b715SmrgSELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
7206747b715Smrg{
7216747b715Smrg    XaceServerAccessRec *rec = calldata;
7226747b715Smrg    SELinuxSubjectRec *subj;
7236747b715Smrg    SELinuxObjectRec *obj;
7246747b715Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
7256747b715Smrg    int rc;
7266747b715Smrg
7276747b715Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
7286747b715Smrg    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
7296747b715Smrg
7306747b715Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode,
7316747b715Smrg			&auditdata);
7326747b715Smrg    if (rc != Success)
7336747b715Smrg	rec->status = rc;
7346747b715Smrg}
7356747b715Smrg
7366747b715Smrg
7376747b715Smrg/*
7386747b715Smrg * DIX Callbacks
7396747b715Smrg */
7406747b715Smrg
7416747b715Smrgstatic void
7426747b715SmrgSELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
7436747b715Smrg{
7446747b715Smrg    NewClientInfoRec *pci = calldata;
7456747b715Smrg
7466747b715Smrg    switch (pci->client->clientState) {
7476747b715Smrg    case ClientStateInitial:
7486747b715Smrg	SELinuxLabelClient(pci->client);
7496747b715Smrg	break;
7506747b715Smrg
7516747b715Smrg    default:
7526747b715Smrg	break;
7536747b715Smrg    }
7546747b715Smrg}
7556747b715Smrg
7566747b715Smrgstatic void
7576747b715SmrgSELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
7586747b715Smrg{
7596747b715Smrg    ResourceStateInfoRec *rec = calldata;
7606747b715Smrg    SELinuxSubjectRec *subj;
7616747b715Smrg    SELinuxObjectRec *obj;
7626747b715Smrg    WindowPtr pWin;
7636747b715Smrg
7646747b715Smrg    if (rec->type != RT_WINDOW)
7656747b715Smrg	return;
7666747b715Smrg    if (rec->state != ResourceStateAdding)
7676747b715Smrg	return;
7686747b715Smrg
7696747b715Smrg    pWin = (WindowPtr)rec->value;
7706747b715Smrg    subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
7716747b715Smrg
7726747b715Smrg    if (subj->sid) {
7736747b715Smrg	security_context_t ctx;
7746747b715Smrg	int rc = avc_sid_to_context_raw(subj->sid, &ctx);
7756747b715Smrg	if (rc < 0)
7766747b715Smrg	    FatalError("SELinux: Failed to get security context!\n");
7776747b715Smrg	rc = dixChangeWindowProperty(serverClient,
7786747b715Smrg				     pWin, atom_client_ctx, XA_STRING, 8,
7796747b715Smrg				     PropModeReplace, strlen(ctx), ctx, FALSE);
7806747b715Smrg	if (rc != Success)
7816747b715Smrg	    FatalError("SELinux: Failed to set label property on window!\n");
7826747b715Smrg	freecon(ctx);
7836747b715Smrg    } else
7846747b715Smrg	FatalError("SELinux: Unexpected unlabeled client found\n");
7856747b715Smrg
7866747b715Smrg    obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
7876747b715Smrg
7886747b715Smrg    if (obj->sid) {
7896747b715Smrg	security_context_t ctx;
7906747b715Smrg	int rc = avc_sid_to_context_raw(obj->sid, &ctx);
7916747b715Smrg	if (rc < 0)
7926747b715Smrg	    FatalError("SELinux: Failed to get security context!\n");
7936747b715Smrg	rc = dixChangeWindowProperty(serverClient,
7946747b715Smrg				     pWin, atom_ctx, XA_STRING, 8,
7956747b715Smrg				     PropModeReplace, strlen(ctx), ctx, FALSE);
7966747b715Smrg	if (rc != Success)
7976747b715Smrg	    FatalError("SELinux: Failed to set label property on window!\n");
7986747b715Smrg	freecon(ctx);
7996747b715Smrg    } else
8006747b715Smrg	FatalError("SELinux: Unexpected unlabeled window found\n");
8016747b715Smrg}
8026747b715Smrg
8036747b715Smrg
8046747b715Smrgstatic int netlink_fd;
8056747b715Smrg
8066747b715Smrgstatic void
8076747b715SmrgSELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask)
8086747b715Smrg{
8096747b715Smrg}
8106747b715Smrg
8116747b715Smrgstatic void
8126747b715SmrgSELinuxWakeupHandler(void *data, int err, void *read_mask)
8136747b715Smrg{
8146747b715Smrg    if (FD_ISSET(netlink_fd, (fd_set *)read_mask))
8156747b715Smrg        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();
8416747b715Smrg    RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
8426747b715Smrg                                 NULL);
8436747b715Smrg    RemoveGeneralSocket(netlink_fd);
8446747b715Smrg
8456747b715Smrg    avc_destroy();
8466747b715Smrg}
8476747b715Smrg
8486747b715Smrgvoid
8496747b715SmrgSELinuxFlaskInit(void)
8506747b715Smrg{
8516747b715Smrg    struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *)0 };
8526747b715Smrg    security_context_t ctx;
8536747b715Smrg    int ret = TRUE;
8546747b715Smrg
8556747b715Smrg    switch(selinuxEnforcingState) {
8566747b715Smrg    case SELINUX_MODE_ENFORCING:
8576747b715Smrg	LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n");
8586747b715Smrg	avc_option.value = (char *)1;
8596747b715Smrg	break;
8606747b715Smrg    case SELINUX_MODE_PERMISSIVE:
8616747b715Smrg	LogMessage(X_INFO, "SELinux: Configured in permissive mode\n");
8626747b715Smrg	avc_option.value = (char *)0;
8636747b715Smrg	break;
8646747b715Smrg    default:
8656747b715Smrg	avc_option.type = AVC_OPT_UNUSED;
8666747b715Smrg	break;
8676747b715Smrg    }
8686747b715Smrg
8696747b715Smrg    /* Set up SELinux stuff */
8706747b715Smrg    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog);
8716747b715Smrg    selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit);
8726747b715Smrg
8736747b715Smrg    if (selinux_set_mapping(map) < 0) {
8746747b715Smrg	if (errno == EINVAL) {
8756747b715Smrg	    ErrorF("SELinux: Invalid object class mapping, disabling SELinux support.\n");
8766747b715Smrg	    return;
8776747b715Smrg	}
8786747b715Smrg	FatalError("SELinux: Failed to set up security class mapping\n");
8796747b715Smrg    }
8806747b715Smrg
8816747b715Smrg    if (avc_open(&avc_option, 1) < 0)
8826747b715Smrg	FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n");
8836747b715Smrg
8846747b715Smrg    if (security_get_initial_context_raw("unlabeled", &ctx) < 0)
8856747b715Smrg	FatalError("SELinux: Failed to look up unlabeled context\n");
8866747b715Smrg    if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0)
8876747b715Smrg	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)
8936747b715Smrg	FatalError("SELinux: Failed to open the system audit log\n");
8946747b715Smrg
8956747b715Smrg    /* Allocate private storage */
8966747b715Smrg    if (!dixRegisterPrivateKey(subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) ||
8976747b715Smrg	!dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec)) ||
8986747b715Smrg	!dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec)))
8996747b715Smrg	FatalError("SELinux: Failed to allocate private storage.\n");
9006747b715Smrg
9016747b715Smrg    /* Create atoms for doing window labeling */
9026747b715Smrg    atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
9036747b715Smrg    if (atom_ctx == BAD_RESOURCE)
9046747b715Smrg	FatalError("SELinux: Failed to create atom\n");
9056747b715Smrg    atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
9066747b715Smrg    if (atom_client_ctx == BAD_RESOURCE)
9076747b715Smrg	FatalError("SELinux: Failed to create atom\n");
9086747b715Smrg
9096747b715Smrg    netlink_fd = avc_netlink_acquire_fd();
9106747b715Smrg    AddGeneralSocket(netlink_fd);
9116747b715Smrg    RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
9126747b715Smrg                                   NULL);
9136747b715Smrg
9146747b715Smrg    /* Register callbacks */
9156747b715Smrg    ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
9166747b715Smrg    ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
9176747b715Smrg
9186747b715Smrg    ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
9196747b715Smrg    ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
9206747b715Smrg    ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
9216747b715Smrg    ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
9226747b715Smrg    ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
9236747b715Smrg    ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
9246747b715Smrg    ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
9256747b715Smrg    ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
9266747b715Smrg    ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
9276747b715Smrg    ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
9286747b715Smrg    ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
9296747b715Smrg    ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
9306747b715Smrg    if (!ret)
9316747b715Smrg	FatalError("SELinux: Failed to register one or more callbacks\n");
9326747b715Smrg
9336747b715Smrg    /* Label objects that were created before we could register ourself */
9346747b715Smrg    SELinuxLabelInitial();
9356747b715Smrg}
936