summaryrefslogtreecommitdiff
path: root/Xext/xselinux.c
diff options
context:
space:
mode:
Diffstat (limited to 'Xext/xselinux.c')
-rw-r--r--Xext/xselinux.c1438
1 files changed, 1438 insertions, 0 deletions
diff --git a/Xext/xselinux.c b/Xext/xselinux.c
new file mode 100644
index 000000000..bbd8d1a46
--- /dev/null
+++ b/Xext/xselinux.c
@@ -0,0 +1,1438 @@
+/************************************************************
+
+Author: Eamon Walsh <ewalsh@epoch.ncsc.mil>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+this permission notice appear in supporting documentation. This permission
+notice shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+********************************************************/
+
+/*
+ * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc.
+ * All rights reserved.
+ */
+
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/avc.h>
+
+#include <libaudit.h>
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/Xatom.h>
+#include "resource.h"
+#include "privates.h"
+#include "registry.h"
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include "scrnintstr.h"
+#include "selection.h"
+#include "xacestr.h"
+#include "xselinux.h"
+#define XSERV_t
+#define TRANS_SERVER
+#include <X11/Xtrans/Xtrans.h>
+#include "../os/osdep.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include "modinit.h"
+
+
+/*
+ * Globals
+ */
+
+/* private state record */
+static DevPrivateKey stateKey = &stateKey;
+
+/* This is what we store for security state */
+typedef struct {
+ security_id_t sid;
+ struct avc_entry_ref aeref;
+ char *command;
+} SELinuxStateRec;
+
+/* selection manager */
+typedef struct {
+ Atom selection;
+ security_id_t sid;
+} SELinuxSelectionRec;
+
+static ClientPtr selectionManager;
+static Window selectionWindow;
+
+/* audit file descriptor */
+static int audit_fd;
+
+/* structure passed to auditing callback */
+typedef struct {
+ ClientPtr client; /* client */
+ char *command; /* client's executable path */
+ unsigned id; /* resource id, if any */
+ int restype; /* resource type, if any */
+ int event; /* event type, if any */
+ Atom property; /* property name, if any */
+ Atom selection; /* selection name, if any */
+ char *extension; /* extension name, if any */
+} SELinuxAuditRec;
+
+/* labeling handle */
+static struct selabel_handle *label_hnd;
+
+/* whether AVC is active */
+static int avc_active;
+
+/* atoms for window label properties */
+static Atom atom_ctx;
+static Atom atom_client_ctx;
+
+/* The unlabeled SID */
+static security_id_t unlabeled_sid;
+
+/* Array of object classes indexed by resource type */
+static security_class_t *knownTypes;
+static unsigned numKnownTypes;
+
+/* Array of event SIDs indexed by event type */
+static security_id_t *knownEvents;
+static unsigned numKnownEvents;
+
+/* Array of selection SID structures */
+static SELinuxSelectionRec *knownSelections;
+static unsigned numKnownSelections;
+
+/* dynamically allocated security classes and permissions */
+static struct security_class_mapping map[] = {
+ { "x_drawable", { "read", "write", "destroy", "create", "getattr", "setattr", "list_property", "get_property", "set_property", "", "", "list_child", "add_child", "remove_child", "hide", "show", "blend", "override", "", "", "", "", "send", "receive", "", "manage", NULL }},
+ { "x_screen", { "", "", "", "", "getattr", "setattr", "saver_getattr", "saver_setattr", "", "", "", "", "", "", "hide_cursor", "show_cursor", "saver_hide", "saver_show", NULL }},
+ { "x_gc", { "", "", "destroy", "create", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_font", { "", "", "destroy", "create", "getattr", "", "", "", "", "", "", "", "add_glyph", "remove_glyph", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_colormap", { "read", "write", "destroy", "create", "getattr", "", "", "", "", "", "", "", "add_color", "remove_color", "", "", "", "", "", "", "install", "uninstall", "", "", "use", NULL }},
+ { "x_property", { "read", "write", "destroy", "create", NULL }},
+ { "x_selection", { "read", "", "", "", "getattr", "setattr", NULL }},
+ { "x_cursor", { "read", "write", "destroy", "create", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_client", { "", "", "destroy", "", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "manage", NULL }},
+ { "x_device", { "read", "write", "", "", "getattr", "setattr", "", "", "", "getfocus", "setfocus", "", "", "", "", "", "", "grab", "freeze", "force_cursor", "", "", "", "", "", "manage", "", "bell", NULL }},
+ { "x_server", { "record", "", "", "", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "grab", "", "", "", "", "", "", "", "manage", "debug", NULL }},
+ { "x_extension", { "", "", "", "", "query", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_event", { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "send", "receive", NULL }},
+ { "x_synthetic_event", { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "send", "receive", NULL }},
+ { "x_resource", { "read", "write", "write", "write", "read", "write", "read", "read", "write", "read", "write", "read", "write", "write", "write", "read", "read", "write", "write", "write", "write", "write", "write", "read", "read", "write", "read", "write", NULL }},
+ { NULL }
+};
+
+/* forward declarations */
+static void SELinuxScreen(CallbackListPtr *, pointer, pointer);
+
+/* "true" pointer value for use as callback data */
+static pointer truep = (pointer)1;
+
+
+/*
+ * Support Routines
+ */
+
+/*
+ * Looks up the SID corresponding to the given selection atom
+ */
+static int
+SELinuxSelectionToSID(Atom selection, SELinuxStateRec *sid_return)
+{
+ const char *name;
+ unsigned i, size;
+
+ for (i = 0; i < numKnownSelections; i++)
+ if (knownSelections[i].selection == selection) {
+ sid_return->sid = knownSelections[i].sid;
+ return Success;
+ }
+
+ /* Need to increase size of array */
+ i = numKnownSelections;
+ size = (i + 1) * sizeof(SELinuxSelectionRec);
+ knownSelections = xrealloc(knownSelections, size);
+ if (!knownSelections)
+ return BadAlloc;
+ knownSelections[i].selection = selection;
+
+ /* Look in the mappings of selection names to contexts */
+ name = NameForAtom(selection);
+ if (name) {
+ security_context_t con;
+ security_id_t sid;
+
+ if (selabel_lookup(label_hnd, &con, name, SELABEL_X_SELN) < 0) {
+ ErrorF("XSELinux: a selection label lookup failed!\n");
+ return BadValue;
+ }
+ /* Get a SID for context */
+ if (avc_context_to_sid(con, &sid) < 0) {
+ ErrorF("XSELinux: a context_to_SID call failed!\n");
+ return BadAlloc;
+ }
+ freecon(con);
+ knownSelections[i].sid = sid_return->sid = sid;
+ } else
+ knownSelections[i].sid = sid_return->sid = unlabeled_sid;
+
+ return Success;
+}
+
+/*
+ * Looks up the SID corresponding to the given event type
+ */
+static int
+SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
+ SELinuxStateRec *sid_return)
+{
+ const char *name = LookupEventName(type);
+ security_context_t con;
+ type &= 127;
+
+ if (type >= numKnownEvents) {
+ /* Need to increase size of classes array */
+ unsigned size = sizeof(security_id_t);
+ knownEvents = xrealloc(knownEvents, (type + 1) * size);
+ if (!knownEvents)
+ return BadAlloc;
+ memset(knownEvents + numKnownEvents, 0,
+ (type - numKnownEvents + 1) * size);
+ numKnownEvents = type + 1;
+ }
+
+ if (!knownEvents[type]) {
+ /* Look in the mappings of event names to contexts */
+ if (selabel_lookup(label_hnd, &con, name, SELABEL_X_EVENT) < 0) {
+ ErrorF("XSELinux: an event label lookup failed!\n");
+ return BadValue;
+ }
+ /* Get a SID for context */
+ if (avc_context_to_sid(con, knownEvents + type) < 0) {
+ ErrorF("XSELinux: a context_to_SID call failed!\n");
+ return BadAlloc;
+ }
+ freecon(con);
+ }
+
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(sid_of_window, knownEvents[type], SECCLASS_X_EVENT,
+ &sid_return->sid) < 0) {
+ ErrorF("XSELinux: a compute_create call failed!\n");
+ return BadValue;
+ }
+
+ return Success;
+}
+
+/*
+ * Returns the object class corresponding to the given resource type.
+ */
+static security_class_t
+SELinuxTypeToClass(RESTYPE type)
+{
+ RESTYPE fulltype = type;
+ type &= TypeMask;
+
+ if (type >= numKnownTypes) {
+ /* Need to increase size of classes array */
+ unsigned size = sizeof(security_class_t);
+ knownTypes = xrealloc(knownTypes, (type + 1) * size);
+ if (!knownTypes)
+ return 0;
+ memset(knownTypes + numKnownTypes, 0,
+ (type - numKnownTypes + 1) * size);
+ numKnownTypes = type + 1;
+ }
+
+ if (!knownTypes[type]) {
+ const char *str;
+ knownTypes[type] = SECCLASS_X_RESOURCE;
+
+ if (fulltype & RC_DRAWABLE)
+ knownTypes[type] = SECCLASS_X_DRAWABLE;
+ if (fulltype == RT_GC)
+ knownTypes[type] = SECCLASS_X_GC;
+ if (fulltype == RT_FONT)
+ knownTypes[type] = SECCLASS_X_FONT;
+ if (fulltype == RT_CURSOR)
+ knownTypes[type] = SECCLASS_X_CURSOR;
+ if (fulltype == RT_COLORMAP)
+ knownTypes[type] = SECCLASS_X_COLORMAP;
+
+ /* Need to do a string lookup */
+ str = LookupResourceName(fulltype);
+ if (!strcmp(str, "PICTURE"))
+ knownTypes[type] = SECCLASS_X_DRAWABLE;
+ if (!strcmp(str, "GLYPHSET"))
+ knownTypes[type] = SECCLASS_X_FONT;
+ }
+
+ return knownTypes[type];
+}
+
+/*
+ * Performs an SELinux permission check.
+ */
+static int
+SELinuxDoCheck(int clientIndex, SELinuxStateRec *subj, SELinuxStateRec *obj,
+ security_class_t class, Mask mode, SELinuxAuditRec *auditdata)
+{
+ /* serverClient requests OK */
+ if (clientIndex == 0)
+ return Success;
+
+ auditdata->command = subj->command;
+ errno = 0;
+
+ if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref,
+ auditdata) < 0) {
+ if (errno == EACCES)
+ return BadAccess;
+ ErrorF("ServerPerm: unexpected error %d\n", errno);
+ return BadValue;
+ }
+
+ return Success;
+}
+
+/*
+ * Labels a newly connected client.
+ */
+static void
+SELinuxLabelClient(ClientPtr client)
+{
+ XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn;
+ SELinuxStateRec *state;
+ security_context_t ctx;
+
+ state = dixLookupPrivate(&client->devPrivates, stateKey);
+ sidput(state->sid);
+
+ if (_XSERVTransIsLocal(ci)) {
+ int fd = _XSERVTransGetConnectionNumber(ci);
+ struct ucred creds;
+ socklen_t len = sizeof(creds);
+ char path[PATH_MAX + 1];
+ size_t bytes;
+
+ /* For local clients, can get context from the socket */
+ if (getpeercon(fd, &ctx) < 0)
+ FatalError("Client %d: couldn't get context from socket\n",
+ client->index);
+
+ /* Try and determine the client's executable name */
+ memset(&creds, 0, sizeof(creds));
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0)
+ goto finish;
+
+ snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto finish;
+
+ bytes = read(fd, path, PATH_MAX + 1);
+ close(fd);
+ if (bytes <= 0)
+ goto finish;
+
+ state->command = xalloc(bytes);
+ if (!state->command)
+ goto finish;
+
+ memcpy(state->command, path, bytes);
+ state->command[bytes - 1] = 0;
+ } else
+ /* For remote clients, need to use a default context */
+ if (selabel_lookup(label_hnd, &ctx, NULL, SELABEL_X_CLIENT) < 0)
+ FatalError("Client %d: couldn't get default remote context\n",
+ client->index);
+
+finish:
+ /* Get a SID from the context */
+ if (avc_context_to_sid(ctx, &state->sid) < 0)
+ FatalError("Client %d: context_to_sid(%s) failed\n",
+ client->index, ctx);
+
+ freecon(ctx);
+}
+
+/*
+ * Labels initial server objects.
+ */
+static void
+SELinuxLabelInitial(void)
+{
+ int i;
+ XaceScreenAccessRec srec;
+ SELinuxStateRec *state;
+ security_context_t ctx;
+ pointer unused;
+
+ /* Do the serverClient */
+ state = dixLookupPrivate(&serverClient->devPrivates, stateKey);
+ sidput(state->sid);
+
+ /* Use the context of the X server process for the serverClient */
+ if (getcon(&ctx) < 0)
+ FatalError("Couldn't get context of X server process\n");
+
+ /* Get a SID from the context */
+ if (avc_context_to_sid(ctx, &state->sid) < 0)
+ FatalError("serverClient: context_to_sid(%s) failed\n", ctx);
+
+ freecon(ctx);
+
+ srec.client = serverClient;
+ srec.access_mode = DixCreateAccess;
+ srec.status = Success;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ /* Do the screen object */
+ srec.screen = screenInfo.screens[i];
+ SELinuxScreen(NULL, NULL, &srec);
+
+ /* Do the default colormap */
+ dixLookupResource(&unused, screenInfo.screens[i]->defColormap,
+ RT_COLORMAP, serverClient, DixCreateAccess);
+ }
+}
+
+
+/*
+ * Libselinux Callbacks
+ */
+
+static int
+SELinuxAudit(void *auditdata,
+ security_class_t class,
+ char *msgbuf,
+ size_t msgbufsize)
+{
+ SELinuxAuditRec *audit = auditdata;
+ ClientPtr client = audit->client;
+ char idNum[16], *propertyName, *selectionName;
+ int major = -1, minor = -1;
+
+ if (client) {
+ REQUEST(xReq);
+ if (stuff) {
+ major = stuff->reqType;
+ minor = MinorOpcodeOfRequest(client);
+ }
+ }
+ if (audit->id)
+ snprintf(idNum, 16, "%x", audit->id);
+
+ propertyName = audit->property ? NameForAtom(audit->property) : NULL;
+ selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
+
+ return snprintf(msgbuf, msgbufsize, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ (major >= 0) ? "request=" : "",
+ (major >= 0) ? LookupRequestName(major, minor) : "",
+ audit->command ? " comm=" : "",
+ audit->command ? audit->command : "",
+ audit->id ? " resid=" : "",
+ audit->id ? idNum : "",
+ audit->restype ? " restype=" : "",
+ audit->restype ? LookupResourceName(audit->restype) : "",
+ audit->event ? " event=" : "",
+ audit->event ? LookupEventName(audit->event & 127) : "",
+ audit->property ? " property=" : "",
+ audit->property ? propertyName : "",
+ audit->selection ? " selection=" : "",
+ audit->selection ? selectionName : "",
+ audit->extension ? " extension=" : "",
+ audit->extension ? audit->extension : "");
+}
+
+static int
+SELinuxLog(int type, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[MAX_AUDIT_MESSAGE_LENGTH];
+ int rc, aut = AUDIT_USER_AVC;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap);
+ rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0);
+ va_end(ap);
+ return 0;
+}
+
+/*
+ * XACE Callbacks
+ */
+
+static void
+SELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceDeviceAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ int rc;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->dev->devPrivates, stateKey);
+
+ /* If this is a new object that needs labeling, do it now */
+ if (rec->access_mode & DixCreateAccess) {
+ sidput(obj->sid);
+
+ /* Label the device directly with the process SID */
+ sidget(subj->sid);
+ obj->sid = subj->sid;
+ }
+
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, SECCLASS_X_DEVICE,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+static void
+SELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceSendAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj, ev_sid;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ security_class_t class;
+ int rc, i, type, clientIndex;
+
+ if (rec->dev) {
+ subj = dixLookupPrivate(&rec->dev->devPrivates, stateKey);
+ clientIndex = -1; /* some nonzero value */
+ } else {
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ clientIndex = rec->client->index;
+ }
+
+ obj = dixLookupPrivate(&rec->pWin->devPrivates, stateKey);
+
+ /* Check send permission on window */
+ rc = SELinuxDoCheck(clientIndex, subj, obj, SECCLASS_X_DRAWABLE,
+ DixSendAccess, &auditdata);
+ if (rc != Success)
+ goto err;
+
+ /* Check send permission on specific event types */
+ for (i = 0; i < rec->count; i++) {
+ type = rec->events[i].u.u.type;
+ class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
+
+ rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
+ if (rc != Success)
+ goto err;
+
+ auditdata.event = type;
+ rc = SELinuxDoCheck(clientIndex, subj, &ev_sid, class,
+ DixSendAccess, &auditdata);
+ if (rc != Success)
+ goto err;
+ }
+ return;
+err:
+ rec->status = rc;
+}
+
+static void
+SELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceReceiveAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj, ev_sid;
+ SELinuxAuditRec auditdata = { .client = NULL };
+ security_class_t class;
+ int rc, i, type;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->pWin->devPrivates, stateKey);
+
+ /* Check receive permission on window */
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, SECCLASS_X_DRAWABLE,
+ DixReceiveAccess, &auditdata);
+ if (rc != Success)
+ goto err;
+
+ /* Check receive permission on specific event types */
+ for (i = 0; i < rec->count; i++) {
+ type = rec->events[i].u.u.type;
+ class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
+
+ rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
+ if (rc != Success)
+ goto err;
+
+ auditdata.event = type;
+ rc = SELinuxDoCheck(rec->client->index, subj, &ev_sid, class,
+ DixReceiveAccess, &auditdata);
+ if (rc != Success)
+ goto err;
+ }
+ return;
+err:
+ rec->status = rc;
+}
+
+static void
+SELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceExtAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj, *serv;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ int rc;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->ext->devPrivates, stateKey);
+
+ /* If this is a new object that needs labeling, do it now */
+ /* XXX there should be a separate callback for this */
+ if (obj->sid == unlabeled_sid) {
+ const char *name = rec->ext->name;
+ security_context_t con;
+ security_id_t sid;
+
+ serv = dixLookupPrivate(&serverClient->devPrivates, stateKey);
+
+ /* Look in the mappings of property names to contexts */
+ if (selabel_lookup(label_hnd, &con, name, SELABEL_X_EXT) < 0) {
+ ErrorF("XSELinux: a property label lookup failed!\n");
+ rec->status = BadValue;
+ return;
+ }
+ /* Get a SID for context */
+ if (avc_context_to_sid(con, &sid) < 0) {
+ ErrorF("XSELinux: a context_to_SID call failed!\n");
+ rec->status = BadAlloc;
+ return;
+ }
+
+ sidput(obj->sid);
+
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
+ &obj->sid) < 0) {
+ ErrorF("XSELinux: a SID transition call failed!\n");
+ freecon(con);
+ rec->status = BadValue;
+ return;
+ }
+ freecon(con);
+ }
+
+ /* Perform the security check */
+ auditdata.extension = rec->ext->name;
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, SECCLASS_X_EXTENSION,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+static void
+SELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XacePropertyAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ int rc;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->pProp->devPrivates, stateKey);
+
+ /* If this is a new object that needs labeling, do it now */
+ if (rec->access_mode & DixCreateAccess) {
+ const char *name = NameForAtom(rec->pProp->propertyName);
+ security_context_t con;
+ security_id_t sid;
+
+ /* Look in the mappings of property names to contexts */
+ if (selabel_lookup(label_hnd, &con, name, SELABEL_X_PROP) < 0) {
+ ErrorF("XSELinux: a property label lookup failed!\n");
+ rec->status = BadValue;
+ return;
+ }
+ /* Get a SID for context */
+ if (avc_context_to_sid(con, &sid) < 0) {
+ ErrorF("XSELinux: a context_to_SID call failed!\n");
+ rec->status = BadAlloc;
+ return;
+ }
+
+ sidput(obj->sid);
+
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(subj->sid, sid, SECCLASS_X_PROPERTY,
+ &obj->sid) < 0) {
+ ErrorF("XSELinux: a SID transition call failed!\n");
+ freecon(con);
+ rec->status = BadValue;
+ return;
+ }
+ freecon(con);
+ avc_entry_ref_init(&obj->aeref);
+ }
+
+ /* Perform the security check */
+ auditdata.property = rec->pProp->propertyName;
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, SECCLASS_X_PROPERTY,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+static void
+SELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceResourceAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj, *pobj;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ PrivateRec **privatePtr;
+ security_class_t class;
+ int rc, offset;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+
+ /* Determine if the resource object has a devPrivates field */
+ offset = dixLookupPrivateOffset(rec->rtype);
+ if (offset < 0) {
+ /* No: use the SID of the owning client */
+ class = SECCLASS_X_RESOURCE;
+ privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
+ obj = dixLookupPrivate(privatePtr, stateKey);
+ } else {
+ /* Yes: use the SID from the resource object itself */
+ class = SELinuxTypeToClass(rec->rtype);
+ privatePtr = DEVPRIV_AT(rec->res, offset);
+ obj = dixLookupPrivate(privatePtr, stateKey);
+ }
+
+ /* If this is a new object that needs labeling, do it now */
+ if (rec->access_mode & DixCreateAccess && offset >= 0) {
+ if (rec->parent)
+ offset = dixLookupPrivateOffset(rec->ptype);
+ if (rec->parent && offset >= 0)
+ /* Use the SID of the parent object in the labeling operation */
+ pobj = dixLookupPrivate(DEVPRIV_AT(rec->parent, offset), stateKey);
+ else
+ /* Use the SID of the subject */
+ pobj = subj;
+
+ sidput(obj->sid);
+
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(subj->sid, pobj->sid, class, &obj->sid) < 0) {
+ ErrorF("XSELinux: a compute_create call failed!\n");
+ rec->status = BadValue;
+ return;
+ }
+ }
+
+ /* Perform the security check */
+ auditdata.restype = rec->rtype;
+ auditdata.id = rec->id;
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, class,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+static void
+SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata)
+{
+ XaceScreenAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ Mask access_mode = rec->access_mode;
+ int rc;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->screen->devPrivates, stateKey);
+
+ /* If this is a new object that needs labeling, do it now */
+ if (access_mode & DixCreateAccess) {
+ sidput(obj->sid);
+
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
+ &obj->sid) < 0) {
+ ErrorF("XSELinux: a compute_create call failed!\n");
+ rec->status = BadValue;
+ return;
+ }
+ }
+
+ if (is_saver)
+ access_mode <<= 2;
+
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, SECCLASS_X_SCREEN,
+ access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+static void
+SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceClientAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ int rc;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->target->devPrivates, stateKey);
+
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, SECCLASS_X_CLIENT,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+static void
+SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceServerAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ int rc;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&serverClient->devPrivates, stateKey);
+
+ rc = SELinuxDoCheck(rec->client->index, subj, obj, SECCLASS_X_SERVER,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+static void
+SELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ XaceSelectionAccessRec *rec = (XaceSelectionAccessRec *)calldata;
+ SELinuxStateRec *subj, sel_sid;
+ SELinuxAuditRec auditdata = { .client = rec->client };
+ int rc;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+
+ rc = SELinuxSelectionToSID(rec->name, &sel_sid);
+ if (rc != Success) {
+ rec->status = rc;
+ return;
+ }
+
+ auditdata.selection = rec->name;
+ rc = SELinuxDoCheck(rec->client->index, subj, &sel_sid,
+ SECCLASS_X_SELECTION, rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
+}
+
+
+/*
+ * DIX Callbacks
+ */
+
+static void
+SELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ NewClientInfoRec *pci = calldata;
+
+ switch (pci->client->clientState) {
+ case ClientStateInitial:
+ SELinuxLabelClient(pci->client);
+ break;
+
+ case ClientStateRetained:
+ case ClientStateGone:
+ if (pci->client == selectionManager) {
+ selectionManager = NULL;
+ selectionWindow = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+SELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ ResourceStateInfoRec *rec = calldata;
+ SELinuxStateRec *state;
+ WindowPtr pWin;
+
+ if (rec->type != RT_WINDOW)
+ return;
+
+ pWin = (WindowPtr)rec->value;
+ state = dixLookupPrivate(&wClient(pWin)->devPrivates, stateKey);
+
+ if (state->sid) {
+ security_context_t ctx;
+ int rc = avc_sid_to_context(state->sid, &ctx);
+ if (rc < 0)
+ FatalError("XSELinux: Failed to get security context!\n");
+ rc = dixChangeWindowProperty(serverClient,
+ pWin, atom_client_ctx, XA_STRING, 8,
+ PropModeReplace, strlen(ctx), ctx, FALSE);
+ if (rc != Success)
+ FatalError("XSELinux: Failed to set label property on window!\n");
+ freecon(ctx);
+ }
+ else
+ FatalError("XSELinux: Unexpected unlabeled client found\n");
+
+ state = dixLookupPrivate(&pWin->devPrivates, stateKey);
+
+ if (state->sid) {
+ security_context_t ctx;
+ int rc = avc_sid_to_context(state->sid, &ctx);
+ if (rc < 0)
+ FatalError("XSELinux: Failed to get security context!\n");
+ rc = dixChangeWindowProperty(serverClient,
+ pWin, atom_ctx, XA_STRING, 8,
+ PropModeReplace, strlen(ctx), ctx, FALSE);
+ if (rc != Success)
+ FatalError("XSELinux: Failed to set label property on window!\n");
+ freecon(ctx);
+ }
+ else
+ FatalError("XSELinux: Unexpected unlabeled window found\n");
+}
+
+static void
+SELinuxSelectionState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ SelectionInfoRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+
+ switch (rec->kind) {
+ case SelectionSetOwner:
+ /* save off the "real" owner of the selection */
+ rec->selection->alt_client = rec->selection->client;
+ rec->selection->alt_window = rec->selection->window;
+
+ /* figure out the new label for the content */
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->selection->devPrivates, stateKey);
+ sidput(obj->sid);
+
+ if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SELECTION,
+ &obj->sid) < 0) {
+ ErrorF("XSELinux: a compute_create call failed!\n");
+ obj->sid = unlabeled_sid;
+ }
+ break;
+
+ case SelectionGetOwner:
+ /* restore the real owner */
+ rec->selection->window = rec->selection->alt_window;
+ break;
+
+ case SelectionConvertSelection:
+ /* redirect the convert request if necessary */
+ if (selectionManager && selectionManager != rec->client) {
+ rec->selection->client = selectionManager;
+ rec->selection->window = selectionWindow;
+ } else {
+ rec->selection->client = rec->selection->alt_client;
+ rec->selection->window = rec->selection->alt_window;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/*
+ * DevPrivates Callbacks
+ */
+
+static void
+SELinuxStateInit(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ PrivateCallbackRec *rec = calldata;
+ SELinuxStateRec *state = *rec->value;
+
+ sidget(unlabeled_sid);
+ state->sid = unlabeled_sid;
+
+ avc_entry_ref_init(&state->aeref);
+}
+
+static void
+SELinuxStateFree(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+{
+ PrivateCallbackRec *rec = calldata;
+ SELinuxStateRec *state = *rec->value;
+
+ xfree(state->command);
+
+ if (avc_active)
+ sidput(state->sid);
+}
+
+
+/*
+ * Extension Dispatch
+ */
+
+static int
+ProcSELinuxQueryVersion(ClientPtr client)
+{
+ SELinuxQueryVersionReply rep;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.server_major = XSELINUX_MAJOR_VERSION;
+ rep.server_minor = XSELINUX_MINOR_VERSION;
+ if (client->swapped) {
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.server_major, n);
+ swaps(&rep.server_minor, n);
+ }
+ WriteToClient(client, sizeof(rep), (char *)&rep);
+ return (client->noClientException);
+}
+
+static int
+ProcSELinuxSetSelectionManager(ClientPtr client)
+{
+ WindowPtr pWin;
+ int rc;
+
+ REQUEST(SELinuxSetSelectionManagerReq);
+ REQUEST_SIZE_MATCH(SELinuxSetSelectionManagerReq);
+
+ if (stuff->window == None) {
+ selectionManager = NULL;
+ selectionWindow = None;
+ } else {
+ rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW,
+ client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ selectionManager = client;
+ selectionWindow = stuff->window;
+ }
+
+ return Success;
+}
+
+static int
+ProcSELinuxGetSelectionManager(ClientPtr client)
+{
+ SELinuxGetSelectionManagerReply rep;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.window = selectionWindow;
+ if (client->swapped) {
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.window, n);
+ }
+ WriteToClient(client, sizeof(rep), (char *)&rep);
+ return (client->noClientException);
+}
+
+static int
+ProcSELinuxSetDeviceCreateContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxGetDeviceCreateContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxSetDeviceContext(ClientPtr client)
+{
+ char *ctx;
+ security_id_t sid;
+ DeviceIntPtr dev;
+ SELinuxStateRec *state;
+ int rc;
+
+ REQUEST(SELinuxSetContextReq);
+ REQUEST_FIXED_SIZE(SELinuxSetContextReq, stuff->context_len);
+
+ ctx = (char *)(stuff + 1);
+ if (ctx[stuff->context_len - 1])
+ return BadLength;
+
+ rc = dixLookupDevice(&dev, stuff->id, client, DixManageAccess);
+ if (rc != Success)
+ return rc;
+
+ rc = avc_context_to_sid(ctx, &sid);
+ if (rc != Success)
+ return BadValue;
+
+ state = dixLookupPrivate(&dev->devPrivates, stateKey);
+ sidput(state->sid);
+ state->sid = sid;
+ return Success;
+}
+
+static int
+ProcSELinuxGetDeviceContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxSetPropertyCreateContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxGetPropertyCreateContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxGetPropertyContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxSetWindowCreateContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxGetWindowCreateContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxGetWindowContext(ClientPtr client)
+{
+ return Success;
+}
+
+static int
+ProcSELinuxDispatch(ClientPtr client)
+{
+ REQUEST(xReq);
+ switch (stuff->data) {
+ case X_SELinuxQueryVersion:
+ return ProcSELinuxQueryVersion(client);
+ case X_SELinuxSetSelectionManager:
+ return ProcSELinuxSetSelectionManager(client);
+ case X_SELinuxGetSelectionManager:
+ return ProcSELinuxGetSelectionManager(client);
+ case X_SELinuxSetDeviceCreateContext:
+ return ProcSELinuxSetDeviceCreateContext(client);
+ case X_SELinuxGetDeviceCreateContext:
+ return ProcSELinuxGetDeviceCreateContext(client);
+ case X_SELinuxSetDeviceContext:
+ return ProcSELinuxSetDeviceContext(client);
+ case X_SELinuxGetDeviceContext:
+ return ProcSELinuxGetDeviceContext(client);
+ case X_SELinuxSetPropertyCreateContext:
+ return ProcSELinuxSetPropertyCreateContext(client);
+ case X_SELinuxGetPropertyCreateContext:
+ return ProcSELinuxGetPropertyCreateContext(client);
+ case X_SELinuxGetPropertyContext:
+ return ProcSELinuxGetPropertyContext(client);
+ case X_SELinuxSetWindowCreateContext:
+ return ProcSELinuxSetWindowCreateContext(client);
+ case X_SELinuxGetWindowCreateContext:
+ return ProcSELinuxGetWindowCreateContext(client);
+ case X_SELinuxGetWindowContext:
+ return ProcSELinuxGetWindowContext(client);
+ default:
+ return BadRequest;
+ }
+}
+
+static int
+SProcSELinuxQueryVersion(ClientPtr client)
+{
+ REQUEST(SELinuxQueryVersionReq);
+ int n;
+
+ REQUEST_SIZE_MATCH (SELinuxQueryVersionReq);
+ swaps(&stuff->client_major,n);
+ swaps(&stuff->client_minor,n);
+ return ProcSELinuxQueryVersion(client);
+}
+
+static int
+SProcSELinuxSetSelectionManager(ClientPtr client)
+{
+ REQUEST(SELinuxSetSelectionManagerReq);
+ int n;
+
+ REQUEST_SIZE_MATCH (SELinuxSetSelectionManagerReq);
+ swapl(&stuff->window,n);
+ return ProcSELinuxSetSelectionManager(client);
+}
+
+static int
+SProcSELinuxGetSelectionManager(ClientPtr client)
+{
+ return ProcSELinuxGetSelectionManager(client);
+}
+
+static int
+SProcSELinuxSetDeviceCreateContext(ClientPtr client)
+{
+ return ProcSELinuxSetDeviceCreateContext(client);
+}
+
+static int
+SProcSELinuxGetDeviceCreateContext(ClientPtr client)
+{
+ return ProcSELinuxGetDeviceCreateContext(client);
+}
+
+static int
+SProcSELinuxSetDeviceContext(ClientPtr client)
+{
+ return ProcSELinuxSetDeviceContext(client);
+}
+
+static int
+SProcSELinuxGetDeviceContext(ClientPtr client)
+{
+ return ProcSELinuxGetDeviceContext(client);
+}
+
+static int
+SProcSELinuxSetPropertyCreateContext(ClientPtr client)
+{
+ return ProcSELinuxSetPropertyCreateContext(client);
+}
+
+static int
+SProcSELinuxGetPropertyCreateContext(ClientPtr client)
+{
+ return ProcSELinuxGetPropertyCreateContext(client);
+}
+
+static int
+SProcSELinuxGetPropertyContext(ClientPtr client)
+{
+ return ProcSELinuxGetPropertyContext(client);
+}
+
+static int
+SProcSELinuxSetWindowCreateContext(ClientPtr client)
+{
+ return ProcSELinuxSetWindowCreateContext(client);
+}
+
+static int
+SProcSELinuxGetWindowCreateContext(ClientPtr client)
+{
+ return ProcSELinuxGetWindowCreateContext(client);
+}
+
+static int
+SProcSELinuxGetWindowContext(ClientPtr client)
+{
+ return ProcSELinuxGetWindowContext(client);
+}
+
+static int
+SProcSELinuxDispatch(ClientPtr client)
+{
+ REQUEST(xReq);
+ int n;
+
+ swaps(&stuff->length, n);
+
+ switch (stuff->data) {
+ case X_SELinuxQueryVersion:
+ return SProcSELinuxQueryVersion(client);
+ case X_SELinuxSetSelectionManager:
+ return SProcSELinuxSetSelectionManager(client);
+ case X_SELinuxGetSelectionManager:
+ return SProcSELinuxGetSelectionManager(client);
+ case X_SELinuxSetDeviceCreateContext:
+ return SProcSELinuxSetDeviceCreateContext(client);
+ case X_SELinuxGetDeviceCreateContext:
+ return SProcSELinuxGetDeviceCreateContext(client);
+ case X_SELinuxSetDeviceContext:
+ return SProcSELinuxSetDeviceContext(client);
+ case X_SELinuxGetDeviceContext:
+ return SProcSELinuxGetDeviceContext(client);
+ case X_SELinuxSetPropertyCreateContext:
+ return SProcSELinuxSetPropertyCreateContext(client);
+ case X_SELinuxGetPropertyCreateContext:
+ return SProcSELinuxGetPropertyCreateContext(client);
+ case X_SELinuxGetPropertyContext:
+ return SProcSELinuxGetPropertyContext(client);
+ case X_SELinuxSetWindowCreateContext:
+ return SProcSELinuxSetWindowCreateContext(client);
+ case X_SELinuxGetWindowCreateContext:
+ return SProcSELinuxGetWindowCreateContext(client);
+ case X_SELinuxGetWindowContext:
+ return SProcSELinuxGetWindowContext(client);
+ default:
+ return BadRequest;
+ }
+}
+
+
+/*
+ * Extension Setup / Teardown
+ */
+
+static void
+SELinuxResetProc(ExtensionEntry *extEntry)
+{
+ /* Unregister callbacks */
+ DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL);
+ DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
+ DeleteCallback(&SelectionCallback, SELinuxSelectionState, NULL);
+
+ XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
+ XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
+ XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
+ XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
+ XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
+ XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
+ XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
+ XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
+ XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
+ XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
+ XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
+ XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
+
+ /* Tear down SELinux stuff */
+ selabel_close(label_hnd);
+ label_hnd = NULL;
+
+ audit_close(audit_fd);
+
+ avc_destroy();
+ avc_active = 0;
+
+ /* Free local state */
+ xfree(knownSelections);
+ knownSelections = NULL;
+ numKnownSelections = 0;
+
+ xfree(knownEvents);
+ knownEvents = NULL;
+ numKnownEvents = 0;
+
+ xfree(knownTypes);
+ knownTypes = NULL;
+ numKnownTypes = 0;
+}
+
+void
+XSELinuxExtensionInit(INITARGS)
+{
+ ExtensionEntry *extEntry;
+ struct selinux_opt options[] = { { SELABEL_OPT_VALIDATE, (char *)1 } };
+ security_context_t con;
+ int ret = TRUE;
+
+ /* Setup SELinux stuff */
+ if (!is_selinux_enabled()) {
+ ErrorF("XSELinux: Extension failed to load: SELinux not enabled\n");
+ return;
+ }
+
+ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog);
+ selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit);
+
+ if (selinux_set_mapping(map) < 0)
+ FatalError("XSELinux: Failed to set up security class mapping\n");
+
+ if (avc_open(NULL, 0) < 0)
+ FatalError("XSELinux: Couldn't initialize SELinux userspace AVC\n");
+ avc_active = 1;
+
+ label_hnd = selabel_open(SELABEL_CTX_X, options, 1);
+ if (!label_hnd)
+ FatalError("XSELinux: Failed to open x_contexts mapping in policy\n");
+
+ if (security_get_initial_context("unlabeled", &con) < 0)
+ FatalError("XSELinux: Failed to look up unlabeled context\n");
+ if (avc_context_to_sid(con, &unlabeled_sid) < 0)
+ FatalError("XSELinux: a context_to_SID call failed!\n");
+ freecon(con);
+
+ /* Prepare for auditing */
+ audit_fd = audit_open();
+ if (audit_fd < 0)
+ FatalError("XSELinux: Failed to open the system audit log\n");
+
+ /* Allocate private storage */
+ if (!dixRequestPrivate(stateKey, sizeof(SELinuxStateRec)))
+ FatalError("XSELinux: Failed to allocate private storage.\n");
+
+ /* Create atoms for doing window labeling */
+ atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
+ if (atom_ctx == BAD_RESOURCE)
+ FatalError("XSELinux: Failed to create atom\n");
+ atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
+ if (atom_client_ctx == BAD_RESOURCE)
+ FatalError("XSELinux: Failed to create atom\n");
+
+ /* Register callbacks */
+ ret &= dixRegisterPrivateInitFunc(stateKey, SELinuxStateInit, NULL);
+ ret &= dixRegisterPrivateDeleteFunc(stateKey, SELinuxStateFree, NULL);
+
+ ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
+ ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
+ ret &= AddCallback(&SelectionCallback, SELinuxSelectionState, NULL);
+
+ ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
+ ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
+ ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
+ ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
+ ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
+ ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
+ ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
+ ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
+ ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
+ ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
+ ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
+ ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
+ if (!ret)
+ FatalError("XSELinux: Failed to register one or more callbacks\n");
+
+ /* Add extension to server */
+ extEntry = AddExtension(XSELINUX_EXTENSION_NAME,
+ XSELinuxNumberEvents, XSELinuxNumberErrors,
+ ProcSELinuxDispatch, SProcSELinuxDispatch,
+ SELinuxResetProc, StandardMinorOpcode);
+
+ /* Label objects that were created before we could register ourself */
+ SELinuxLabelInitial();
+}