1706f2543Smrg/************************************************************
2706f2543Smrg
3706f2543SmrgAuthor: Eamon Walsh <ewalsh@tycho.nsa.gov>
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthis permission notice appear in supporting documentation.  This permission
8706f2543Smrgnotice shall be included in all copies or substantial portions of the
9706f2543SmrgSoftware.
10706f2543Smrg
11706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
14706f2543SmrgAUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17706f2543Smrg
18706f2543Smrg********************************************************/
19706f2543Smrg
20706f2543Smrg/*
21706f2543Smrg * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc.
22706f2543Smrg * All rights reserved.
23706f2543Smrg */
24706f2543Smrg
25706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
26706f2543Smrg#include <dix-config.h>
27706f2543Smrg#endif
28706f2543Smrg
29706f2543Smrg#include <sys/socket.h>
30706f2543Smrg#include <stdio.h>
31706f2543Smrg#include <stdarg.h>
32706f2543Smrg
33706f2543Smrg#include <libaudit.h>
34706f2543Smrg
35706f2543Smrg#include <X11/Xatom.h>
36706f2543Smrg#include "selection.h"
37706f2543Smrg#include "inputstr.h"
38706f2543Smrg#include "scrnintstr.h"
39706f2543Smrg#include "windowstr.h"
40706f2543Smrg#include "propertyst.h"
41706f2543Smrg#include "extnsionst.h"
42706f2543Smrg#include "xacestr.h"
43706f2543Smrg#include "../os/osdep.h"
44706f2543Smrg#define _XSELINUX_NEED_FLASK_MAP
45706f2543Smrg#include "xselinuxint.h"
46706f2543Smrg
47706f2543Smrg
48706f2543Smrg/* structure passed to auditing callback */
49706f2543Smrgtypedef struct {
50706f2543Smrg    ClientPtr client;	/* client */
51706f2543Smrg    DeviceIntPtr dev;	/* device */
52706f2543Smrg    char *command;	/* client's executable path */
53706f2543Smrg    unsigned id;	/* resource id, if any */
54706f2543Smrg    int restype;	/* resource type, if any */
55706f2543Smrg    int event;		/* event type, if any */
56706f2543Smrg    Atom property;	/* property name, if any */
57706f2543Smrg    Atom selection;	/* selection name, if any */
58706f2543Smrg    char *extension;	/* extension name, if any */
59706f2543Smrg} SELinuxAuditRec;
60706f2543Smrg
61706f2543Smrg/* private state keys */
62706f2543SmrgDevPrivateKeyRec subjectKeyRec;
63706f2543SmrgDevPrivateKeyRec objectKeyRec;
64706f2543SmrgDevPrivateKeyRec dataKeyRec;
65706f2543Smrg
66706f2543Smrg/* audit file descriptor */
67706f2543Smrgstatic int audit_fd;
68706f2543Smrg
69706f2543Smrg/* atoms for window label properties */
70706f2543Smrgstatic Atom atom_ctx;
71706f2543Smrgstatic Atom atom_client_ctx;
72706f2543Smrg
73706f2543Smrg/* The unlabeled SID */
74706f2543Smrgstatic security_id_t unlabeled_sid;
75706f2543Smrg
76706f2543Smrg/* forward declarations */
77706f2543Smrgstatic void SELinuxScreen(CallbackListPtr *, pointer, pointer);
78706f2543Smrg
79706f2543Smrg/* "true" pointer value for use as callback data */
80706f2543Smrgstatic pointer truep = (pointer)1;
81706f2543Smrg
82706f2543Smrg
83706f2543Smrg/*
84706f2543Smrg * Performs an SELinux permission check.
85706f2543Smrg */
86706f2543Smrgstatic int
87706f2543SmrgSELinuxDoCheck(SELinuxSubjectRec *subj, SELinuxObjectRec *obj,
88706f2543Smrg	       security_class_t class, Mask mode, SELinuxAuditRec *auditdata)
89706f2543Smrg{
90706f2543Smrg    /* serverClient requests OK */
91706f2543Smrg    if (subj->privileged)
92706f2543Smrg	return Success;
93706f2543Smrg
94706f2543Smrg    auditdata->command = subj->command;
95706f2543Smrg    errno = 0;
96706f2543Smrg
97706f2543Smrg    if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref,
98706f2543Smrg		     auditdata) < 0) {
99706f2543Smrg	if (mode == DixUnknownAccess)
100706f2543Smrg	    return Success; /* DixUnknownAccess requests OK ... for now */
101706f2543Smrg	if (errno == EACCES)
102706f2543Smrg	    return BadAccess;
103706f2543Smrg	ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno);
104706f2543Smrg	return BadValue;
105706f2543Smrg    }
106706f2543Smrg
107706f2543Smrg    return Success;
108706f2543Smrg}
109706f2543Smrg
110706f2543Smrg/*
111706f2543Smrg * Labels a newly connected client.
112706f2543Smrg */
113706f2543Smrgstatic void
114706f2543SmrgSELinuxLabelClient(ClientPtr client)
115706f2543Smrg{
116706f2543Smrg    int fd = XaceGetConnectionNumber(client);
117706f2543Smrg    SELinuxSubjectRec *subj;
118706f2543Smrg    SELinuxObjectRec *obj;
119706f2543Smrg    security_context_t ctx;
120706f2543Smrg
121706f2543Smrg    subj = dixLookupPrivate(&client->devPrivates, subjectKey);
122706f2543Smrg    obj = dixLookupPrivate(&client->devPrivates, objectKey);
123706f2543Smrg
124706f2543Smrg    /* Try to get a context from the socket */
125706f2543Smrg    if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) {
126706f2543Smrg	/* Otherwise, fall back to a default context */
127706f2543Smrg	ctx = SELinuxDefaultClientLabel();
128706f2543Smrg    }
129706f2543Smrg
130706f2543Smrg    /* For local clients, try and determine the executable name */
131706f2543Smrg    if (XaceIsLocal(client)) {
132706f2543Smrg	struct ucred creds;
133706f2543Smrg	socklen_t len = sizeof(creds);
134706f2543Smrg	char path[PATH_MAX + 1];
135706f2543Smrg	size_t bytes;
136706f2543Smrg
137706f2543Smrg	memset(&creds, 0, sizeof(creds));
138706f2543Smrg	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0)
139706f2543Smrg	    goto finish;
140706f2543Smrg
141706f2543Smrg	snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid);
142706f2543Smrg	fd = open(path, O_RDONLY);
143706f2543Smrg	if (fd < 0)
144706f2543Smrg	    goto finish;
145706f2543Smrg
146706f2543Smrg	bytes = read(fd, path, PATH_MAX + 1);
147706f2543Smrg	close(fd);
148706f2543Smrg	if (bytes <= 0)
149706f2543Smrg	    goto finish;
150706f2543Smrg
151706f2543Smrg	strncpy(subj->command, path, COMMAND_LEN - 1);
152706f2543Smrg    }
153706f2543Smrg
154706f2543Smrgfinish:
155706f2543Smrg    /* Get a SID from the context */
156706f2543Smrg    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
157706f2543Smrg	FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n",
158706f2543Smrg		   client->index, ctx);
159706f2543Smrg
160706f2543Smrg    obj->sid = subj->sid;
161706f2543Smrg    freecon(ctx);
162706f2543Smrg}
163706f2543Smrg
164706f2543Smrg/*
165706f2543Smrg * Labels initial server objects.
166706f2543Smrg */
167706f2543Smrgstatic void
168706f2543SmrgSELinuxLabelInitial(void)
169706f2543Smrg{
170706f2543Smrg    int i;
171706f2543Smrg    XaceScreenAccessRec srec;
172706f2543Smrg    SELinuxSubjectRec *subj;
173706f2543Smrg    SELinuxObjectRec *obj;
174706f2543Smrg    security_context_t ctx;
175706f2543Smrg    pointer unused;
176706f2543Smrg
177706f2543Smrg    /* Do the serverClient */
178706f2543Smrg    subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
179706f2543Smrg    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
180706f2543Smrg    subj->privileged = 1;
181706f2543Smrg
182706f2543Smrg    /* Use the context of the X server process for the serverClient */
183706f2543Smrg    if (getcon_raw(&ctx) < 0)
184706f2543Smrg	FatalError("SELinux: couldn't get context of X server process\n");
185706f2543Smrg
186706f2543Smrg    /* Get a SID from the context */
187706f2543Smrg    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
188706f2543Smrg	FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx);
189706f2543Smrg
190706f2543Smrg    obj->sid = subj->sid;
191706f2543Smrg    freecon(ctx);
192706f2543Smrg
193706f2543Smrg    srec.client = serverClient;
194706f2543Smrg    srec.access_mode = DixCreateAccess;
195706f2543Smrg    srec.status = Success;
196706f2543Smrg
197706f2543Smrg    for (i = 0; i < screenInfo.numScreens; i++) {
198706f2543Smrg	/* Do the screen object */
199706f2543Smrg	srec.screen = screenInfo.screens[i];
200706f2543Smrg	SELinuxScreen(NULL, NULL, &srec);
201706f2543Smrg
202706f2543Smrg	/* Do the default colormap */
203706f2543Smrg	dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap,
204706f2543Smrg			  RT_COLORMAP, serverClient, DixCreateAccess);
205706f2543Smrg    }
206706f2543Smrg}
207706f2543Smrg
208706f2543Smrg/*
209706f2543Smrg * Labels new resource objects.
210706f2543Smrg */
211706f2543Smrgstatic int
212706f2543SmrgSELinuxLabelResource(XaceResourceAccessRec *rec, SELinuxSubjectRec *subj,
213706f2543Smrg		     SELinuxObjectRec *obj, security_class_t class)
214706f2543Smrg{
215706f2543Smrg    int offset;
216706f2543Smrg    security_id_t tsid;
217706f2543Smrg
218706f2543Smrg    /* Check for a create context */
219706f2543Smrg    if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) {
220706f2543Smrg	obj->sid = subj->win_create_sid;
221706f2543Smrg	return Success;
222706f2543Smrg    }
223706f2543Smrg
224706f2543Smrg    if (rec->parent)
225706f2543Smrg	offset = dixLookupPrivateOffset(rec->ptype);
226706f2543Smrg
227706f2543Smrg    if (rec->parent && offset >= 0) {
228706f2543Smrg	/* Use the SID of the parent object in the labeling operation */
229706f2543Smrg	PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset);
230706f2543Smrg	SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey);
231706f2543Smrg	tsid = pobj->sid;
232706f2543Smrg    } else {
233706f2543Smrg	/* Use the SID of the subject */
234706f2543Smrg	tsid = subj->sid;
235706f2543Smrg    }
236706f2543Smrg
237706f2543Smrg    /* Perform a transition to obtain the final SID */
238706f2543Smrg    if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) {
239706f2543Smrg	ErrorF("SELinux: a compute_create call failed!\n");
240706f2543Smrg	return BadValue;
241706f2543Smrg    }
242706f2543Smrg
243706f2543Smrg    return Success;
244706f2543Smrg}
245706f2543Smrg
246706f2543Smrg
247706f2543Smrg/*
248706f2543Smrg * Libselinux Callbacks
249706f2543Smrg */
250706f2543Smrg
251706f2543Smrgstatic int
252706f2543SmrgSELinuxAudit(void *auditdata,
253706f2543Smrg	     security_class_t class,
254706f2543Smrg	     char *msgbuf,
255706f2543Smrg	     size_t msgbufsize)
256706f2543Smrg{
257706f2543Smrg    SELinuxAuditRec *audit = auditdata;
258706f2543Smrg    ClientPtr client = audit->client;
259706f2543Smrg    char idNum[16];
260706f2543Smrg    const char *propertyName, *selectionName;
261706f2543Smrg    int major = -1, minor = -1;
262706f2543Smrg
263706f2543Smrg    if (client) {
264706f2543Smrg	REQUEST(xReq);
265706f2543Smrg	if (stuff) {
266706f2543Smrg	    major = stuff->reqType;
267706f2543Smrg	    minor = MinorOpcodeOfRequest(client);
268706f2543Smrg	}
269706f2543Smrg    }
270706f2543Smrg    if (audit->id)
271706f2543Smrg	snprintf(idNum, 16, "%x", audit->id);
272706f2543Smrg
273706f2543Smrg    propertyName = audit->property ? NameForAtom(audit->property) : NULL;
274706f2543Smrg    selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
275706f2543Smrg
276706f2543Smrg    return snprintf(msgbuf, msgbufsize,
277706f2543Smrg		    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
278706f2543Smrg		    (major >= 0) ? "request=" : "",
279706f2543Smrg		    (major >= 0) ? LookupRequestName(major, minor) : "",
280706f2543Smrg		    audit->command ? " comm=" : "",
281706f2543Smrg		    audit->command ? audit->command : "",
282706f2543Smrg		    audit->dev ? " xdevice=\"" : "",
283706f2543Smrg		    audit->dev ? audit->dev->name : "",
284706f2543Smrg		    audit->dev ? "\"" : "",
285706f2543Smrg		    audit->id ? " resid=" : "",
286706f2543Smrg		    audit->id ? idNum : "",
287706f2543Smrg		    audit->restype ? " restype=" : "",
288706f2543Smrg		    audit->restype ? LookupResourceName(audit->restype) : "",
289706f2543Smrg		    audit->event ? " event=" : "",
290706f2543Smrg		    audit->event ? LookupEventName(audit->event & 127) : "",
291706f2543Smrg		    audit->property ? " property=" : "",
292706f2543Smrg		    audit->property ? propertyName : "",
293706f2543Smrg		    audit->selection ? " selection=" : "",
294706f2543Smrg		    audit->selection ? selectionName : "",
295706f2543Smrg		    audit->extension ? " extension=" : "",
296706f2543Smrg		    audit->extension ? audit->extension : "");
297706f2543Smrg}
298706f2543Smrg
299706f2543Smrgstatic int
300706f2543SmrgSELinuxLog(int type, const char *fmt, ...)
301706f2543Smrg{
302706f2543Smrg    va_list ap;
303706f2543Smrg    char buf[MAX_AUDIT_MESSAGE_LENGTH];
304706f2543Smrg    int rc, aut;
305706f2543Smrg
306706f2543Smrg    switch (type) {
307706f2543Smrg    case SELINUX_INFO:
308706f2543Smrg	aut = AUDIT_USER_MAC_POLICY_LOAD;
309706f2543Smrg	break;
310706f2543Smrg    case SELINUX_AVC:
311706f2543Smrg	aut = AUDIT_USER_AVC;
312706f2543Smrg	break;
313706f2543Smrg    default:
314706f2543Smrg	aut = AUDIT_USER_SELINUX_ERR;
315706f2543Smrg	break;
316706f2543Smrg    }
317706f2543Smrg
318706f2543Smrg    va_start(ap, fmt);
319706f2543Smrg    vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap);
320706f2543Smrg    rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0);
321706f2543Smrg    va_end(ap);
322706f2543Smrg    LogMessageVerb(X_WARNING, 0, "%s", buf);
323706f2543Smrg    return 0;
324706f2543Smrg}
325706f2543Smrg
326706f2543Smrg/*
327706f2543Smrg * XACE Callbacks
328706f2543Smrg */
329706f2543Smrg
330706f2543Smrgstatic void
331706f2543SmrgSELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata)
332706f2543Smrg{
333706f2543Smrg    XaceDeviceAccessRec *rec = calldata;
334706f2543Smrg    SELinuxSubjectRec *subj;
335706f2543Smrg    SELinuxObjectRec *obj;
336706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev };
337706f2543Smrg    security_class_t cls;
338706f2543Smrg    int rc;
339706f2543Smrg
340706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
341706f2543Smrg    obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey);
342706f2543Smrg
343706f2543Smrg    /* If this is a new object that needs labeling, do it now */
344706f2543Smrg    if (rec->access_mode & DixCreateAccess) {
345706f2543Smrg	SELinuxSubjectRec *dsubj;
346706f2543Smrg	dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
347706f2543Smrg
348706f2543Smrg	if (subj->dev_create_sid) {
349706f2543Smrg	    /* Label the device with the create context */
350706f2543Smrg	    obj->sid = subj->dev_create_sid;
351706f2543Smrg	    dsubj->sid = subj->dev_create_sid;
352706f2543Smrg	} else {
353706f2543Smrg	    /* Label the device directly with the process SID */
354706f2543Smrg	    obj->sid = subj->sid;
355706f2543Smrg	    dsubj->sid = subj->sid;
356706f2543Smrg	}
357706f2543Smrg    }
358706f2543Smrg
359706f2543Smrg    cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD;
360706f2543Smrg    rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata);
361706f2543Smrg    if (rc != Success)
362706f2543Smrg	rec->status = rc;
363706f2543Smrg}
364706f2543Smrg
365706f2543Smrgstatic void
366706f2543SmrgSELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata)
367706f2543Smrg{
368706f2543Smrg    XaceSendAccessRec *rec = calldata;
369706f2543Smrg    SELinuxSubjectRec *subj;
370706f2543Smrg    SELinuxObjectRec *obj, ev_sid;
371706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev };
372706f2543Smrg    security_class_t class;
373706f2543Smrg    int rc, i, type;
374706f2543Smrg
375706f2543Smrg    if (rec->dev)
376706f2543Smrg	subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
377706f2543Smrg    else
378706f2543Smrg	subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
379706f2543Smrg
380706f2543Smrg    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
381706f2543Smrg
382706f2543Smrg    /* Check send permission on window */
383706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess,
384706f2543Smrg			&auditdata);
385706f2543Smrg    if (rc != Success)
386706f2543Smrg	goto err;
387706f2543Smrg
388706f2543Smrg    /* Check send permission on specific event types */
389706f2543Smrg    for (i = 0; i < rec->count; i++) {
390706f2543Smrg	type = rec->events[i].u.u.type;
391706f2543Smrg	class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
392706f2543Smrg
393706f2543Smrg	rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
394706f2543Smrg	if (rc != Success)
395706f2543Smrg	    goto err;
396706f2543Smrg
397706f2543Smrg	auditdata.event = type;
398706f2543Smrg	rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata);
399706f2543Smrg	if (rc != Success)
400706f2543Smrg	    goto err;
401706f2543Smrg    }
402706f2543Smrg    return;
403706f2543Smrgerr:
404706f2543Smrg    rec->status = rc;
405706f2543Smrg}
406706f2543Smrg
407706f2543Smrgstatic void
408706f2543SmrgSELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata)
409706f2543Smrg{
410706f2543Smrg    XaceReceiveAccessRec *rec = calldata;
411706f2543Smrg    SELinuxSubjectRec *subj;
412706f2543Smrg    SELinuxObjectRec *obj, ev_sid;
413706f2543Smrg    SELinuxAuditRec auditdata = { .client = NULL };
414706f2543Smrg    security_class_t class;
415706f2543Smrg    int rc, i, type;
416706f2543Smrg
417706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
418706f2543Smrg    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
419706f2543Smrg
420706f2543Smrg    /* Check receive permission on window */
421706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess,
422706f2543Smrg			&auditdata);
423706f2543Smrg    if (rc != Success)
424706f2543Smrg	goto err;
425706f2543Smrg
426706f2543Smrg    /* Check receive permission on specific event types */
427706f2543Smrg    for (i = 0; i < rec->count; i++) {
428706f2543Smrg	type = rec->events[i].u.u.type;
429706f2543Smrg	class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
430706f2543Smrg
431706f2543Smrg	rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
432706f2543Smrg	if (rc != Success)
433706f2543Smrg	    goto err;
434706f2543Smrg
435706f2543Smrg	auditdata.event = type;
436706f2543Smrg	rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata);
437706f2543Smrg	if (rc != Success)
438706f2543Smrg	    goto err;
439706f2543Smrg    }
440706f2543Smrg    return;
441706f2543Smrgerr:
442706f2543Smrg    rec->status = rc;
443706f2543Smrg}
444706f2543Smrg
445706f2543Smrgstatic void
446706f2543SmrgSELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata)
447706f2543Smrg{
448706f2543Smrg    XaceExtAccessRec *rec = calldata;
449706f2543Smrg    SELinuxSubjectRec *subj, *serv;
450706f2543Smrg    SELinuxObjectRec *obj;
451706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
452706f2543Smrg    int rc;
453706f2543Smrg
454706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
455706f2543Smrg    obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey);
456706f2543Smrg
457706f2543Smrg    /* If this is a new object that needs labeling, do it now */
458706f2543Smrg    /* XXX there should be a separate callback for this */
459706f2543Smrg    if (obj->sid == NULL) {
460706f2543Smrg	security_id_t sid;
461706f2543Smrg
462706f2543Smrg	serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
463706f2543Smrg	rc = SELinuxExtensionToSID(rec->ext->name, &sid);
464706f2543Smrg	if (rc != Success) {
465706f2543Smrg	    rec->status = rc;
466706f2543Smrg	    return;
467706f2543Smrg	}
468706f2543Smrg
469706f2543Smrg	/* Perform a transition to obtain the final SID */
470706f2543Smrg	if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
471706f2543Smrg			       &obj->sid) < 0) {
472706f2543Smrg	    ErrorF("SELinux: a SID transition call failed!\n");
473706f2543Smrg	    rec->status = BadValue;
474706f2543Smrg	    return;
475706f2543Smrg	}
476706f2543Smrg    }
477706f2543Smrg
478706f2543Smrg    /* Perform the security check */
479706f2543Smrg    auditdata.extension = rec->ext->name;
480706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode,
481706f2543Smrg			&auditdata);
482706f2543Smrg    if (rc != Success)
483706f2543Smrg	rec->status = rc;
484706f2543Smrg}
485706f2543Smrg
486706f2543Smrgstatic void
487706f2543SmrgSELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata)
488706f2543Smrg{
489706f2543Smrg    XaceSelectionAccessRec *rec = calldata;
490706f2543Smrg    SELinuxSubjectRec *subj;
491706f2543Smrg    SELinuxObjectRec *obj, *data;
492706f2543Smrg    Selection *pSel = *rec->ppSel;
493706f2543Smrg    Atom name = pSel->selection;
494706f2543Smrg    Mask access_mode = rec->access_mode;
495706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .selection = name };
496706f2543Smrg    security_id_t tsid;
497706f2543Smrg    int rc;
498706f2543Smrg
499706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
500706f2543Smrg    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
501706f2543Smrg
502706f2543Smrg    /* If this is a new object that needs labeling, do it now */
503706f2543Smrg    if (access_mode & DixCreateAccess) {
504706f2543Smrg	rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly);
505706f2543Smrg	if (rc != Success)
506706f2543Smrg	    obj->sid = unlabeled_sid;
507706f2543Smrg	access_mode = DixSetAttrAccess;
508706f2543Smrg    }
509706f2543Smrg    /* If this is a polyinstantiated object, find the right instance */
510706f2543Smrg    else if (obj->poly) {
511706f2543Smrg	rc = SELinuxSelectionToSID(name, subj, &tsid, NULL);
512706f2543Smrg	if (rc != Success) {
513706f2543Smrg	    rec->status = rc;
514706f2543Smrg	    return;
515706f2543Smrg	}
516706f2543Smrg	while (pSel->selection != name || obj->sid != tsid) {
517706f2543Smrg	    if ((pSel = pSel->next) == NULL)
518706f2543Smrg		break;
519706f2543Smrg	    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
520706f2543Smrg	}
521706f2543Smrg
522706f2543Smrg	if (pSel)
523706f2543Smrg	    *rec->ppSel = pSel;
524706f2543Smrg	else {
525706f2543Smrg	    rec->status = BadMatch;
526706f2543Smrg	    return;
527706f2543Smrg	}
528706f2543Smrg    }
529706f2543Smrg
530706f2543Smrg    /* Perform the security check */
531706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode,
532706f2543Smrg			&auditdata);
533706f2543Smrg    if (rc != Success)
534706f2543Smrg	rec->status = rc;
535706f2543Smrg
536706f2543Smrg    /* Label the content (advisory only) */
537706f2543Smrg    if (access_mode & DixSetAttrAccess) {
538706f2543Smrg	data = dixLookupPrivate(&pSel->devPrivates, dataKey);
539706f2543Smrg	if (subj->sel_create_sid)
540706f2543Smrg	    data->sid = subj->sel_create_sid;
541706f2543Smrg	else
542706f2543Smrg	    data->sid = obj->sid;
543706f2543Smrg    }
544706f2543Smrg}
545706f2543Smrg
546706f2543Smrgstatic void
547706f2543SmrgSELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata)
548706f2543Smrg{
549706f2543Smrg    XacePropertyAccessRec *rec = calldata;
550706f2543Smrg    SELinuxSubjectRec *subj;
551706f2543Smrg    SELinuxObjectRec *obj, *data;
552706f2543Smrg    PropertyPtr pProp = *rec->ppProp;
553706f2543Smrg    Atom name = pProp->propertyName;
554706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client, .property = name };
555706f2543Smrg    security_id_t tsid;
556706f2543Smrg    int rc;
557706f2543Smrg
558706f2543Smrg    /* Don't care about the new content check */
559706f2543Smrg    if (rec->access_mode & DixPostAccess)
560706f2543Smrg	return;
561706f2543Smrg
562706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
563706f2543Smrg    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
564706f2543Smrg
565706f2543Smrg    /* If this is a new object that needs labeling, do it now */
566706f2543Smrg    if (rec->access_mode & DixCreateAccess) {
567706f2543Smrg	rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly);
568706f2543Smrg	if (rc != Success) {
569706f2543Smrg	    rec->status = rc;
570706f2543Smrg	    return;
571706f2543Smrg	}
572706f2543Smrg    }
573706f2543Smrg    /* If this is a polyinstantiated object, find the right instance */
574706f2543Smrg    else if (obj->poly) {
575706f2543Smrg	rc = SELinuxPropertyToSID(name, subj, &tsid, NULL);
576706f2543Smrg	if (rc != Success) {
577706f2543Smrg	    rec->status = rc;
578706f2543Smrg	    return;
579706f2543Smrg	}
580706f2543Smrg	while (pProp->propertyName != name || obj->sid != tsid) {
581706f2543Smrg	    if ((pProp = pProp->next) == NULL)
582706f2543Smrg		break;
583706f2543Smrg	    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
584706f2543Smrg	}
585706f2543Smrg
586706f2543Smrg	if (pProp)
587706f2543Smrg	    *rec->ppProp = pProp;
588706f2543Smrg	else {
589706f2543Smrg	    rec->status = BadMatch;
590706f2543Smrg	    return;
591706f2543Smrg	}
592706f2543Smrg    }
593706f2543Smrg
594706f2543Smrg    /* Perform the security check */
595706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode,
596706f2543Smrg			&auditdata);
597706f2543Smrg    if (rc != Success)
598706f2543Smrg	rec->status = rc;
599706f2543Smrg
600706f2543Smrg    /* Label the content (advisory only) */
601706f2543Smrg    if (rec->access_mode & DixWriteAccess) {
602706f2543Smrg	data = dixLookupPrivate(&pProp->devPrivates, dataKey);
603706f2543Smrg	if (subj->prp_create_sid)
604706f2543Smrg	    data->sid = subj->prp_create_sid;
605706f2543Smrg	else
606706f2543Smrg	    data->sid = obj->sid;
607706f2543Smrg    }
608706f2543Smrg}
609706f2543Smrg
610706f2543Smrgstatic void
611706f2543SmrgSELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata)
612706f2543Smrg{
613706f2543Smrg    XaceResourceAccessRec *rec = calldata;
614706f2543Smrg    SELinuxSubjectRec *subj;
615706f2543Smrg    SELinuxObjectRec *obj;
616706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
617706f2543Smrg    Mask access_mode = rec->access_mode;
618706f2543Smrg    PrivateRec **privatePtr;
619706f2543Smrg    security_class_t class;
620706f2543Smrg    int rc, offset;
621706f2543Smrg
622706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
623706f2543Smrg
624706f2543Smrg    /* Determine if the resource object has a devPrivates field */
625706f2543Smrg    offset = dixLookupPrivateOffset(rec->rtype);
626706f2543Smrg    if (offset < 0) {
627706f2543Smrg	/* No: use the SID of the owning client */
628706f2543Smrg	class = SECCLASS_X_RESOURCE;
629706f2543Smrg	privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
630706f2543Smrg	obj = dixLookupPrivate(privatePtr, objectKey);
631706f2543Smrg    } else {
632706f2543Smrg	/* Yes: use the SID from the resource object itself */
633706f2543Smrg	class = SELinuxTypeToClass(rec->rtype);
634706f2543Smrg	privatePtr = DEVPRIV_AT(rec->res, offset);
635706f2543Smrg	obj = dixLookupPrivate(privatePtr, objectKey);
636706f2543Smrg    }
637706f2543Smrg
638706f2543Smrg    /* If this is a new object that needs labeling, do it now */
639706f2543Smrg    if (access_mode & DixCreateAccess && offset >= 0) {
640706f2543Smrg	rc = SELinuxLabelResource(rec, subj, obj, class);
641706f2543Smrg	if (rc != Success) {
642706f2543Smrg	    rec->status = rc;
643706f2543Smrg	    return;
644706f2543Smrg	}
645706f2543Smrg    }
646706f2543Smrg
647706f2543Smrg    /* Collapse generic resource permissions down to read/write */
648706f2543Smrg    if (class == SECCLASS_X_RESOURCE) {
649706f2543Smrg	access_mode = !!(rec->access_mode & SELinuxReadMask); /* rd */
650706f2543Smrg	access_mode |= !!(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */
651706f2543Smrg    }
652706f2543Smrg
653706f2543Smrg    /* Perform the security check */
654706f2543Smrg    auditdata.restype = rec->rtype;
655706f2543Smrg    auditdata.id = rec->id;
656706f2543Smrg    rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata);
657706f2543Smrg    if (rc != Success)
658706f2543Smrg	rec->status = rc;
659706f2543Smrg
660706f2543Smrg    /* Perform the background none check on windows */
661706f2543Smrg    if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) {
662706f2543Smrg	rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata);
663706f2543Smrg	if (rc != Success)
664706f2543Smrg	    ((WindowPtr)rec->res)->forcedBG = TRUE;
665706f2543Smrg    }
666706f2543Smrg}
667706f2543Smrg
668706f2543Smrgstatic void
669706f2543SmrgSELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata)
670706f2543Smrg{
671706f2543Smrg    XaceScreenAccessRec *rec = calldata;
672706f2543Smrg    SELinuxSubjectRec *subj;
673706f2543Smrg    SELinuxObjectRec *obj;
674706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
675706f2543Smrg    Mask access_mode = rec->access_mode;
676706f2543Smrg    int rc;
677706f2543Smrg
678706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
679706f2543Smrg    obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey);
680706f2543Smrg
681706f2543Smrg    /* If this is a new object that needs labeling, do it now */
682706f2543Smrg    if (access_mode & DixCreateAccess) {
683706f2543Smrg	/* Perform a transition to obtain the final SID */
684706f2543Smrg	if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
685706f2543Smrg			       &obj->sid) < 0) {
686706f2543Smrg	    ErrorF("SELinux: a compute_create call failed!\n");
687706f2543Smrg	    rec->status = BadValue;
688706f2543Smrg	    return;
689706f2543Smrg	}
690706f2543Smrg    }
691706f2543Smrg
692706f2543Smrg    if (is_saver)
693706f2543Smrg	access_mode <<= 2;
694706f2543Smrg
695706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata);
696706f2543Smrg    if (rc != Success)
697706f2543Smrg	rec->status = rc;
698706f2543Smrg}
699706f2543Smrg
700706f2543Smrgstatic void
701706f2543SmrgSELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata)
702706f2543Smrg{
703706f2543Smrg    XaceClientAccessRec *rec = calldata;
704706f2543Smrg    SELinuxSubjectRec *subj;
705706f2543Smrg    SELinuxObjectRec *obj;
706706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
707706f2543Smrg    int rc;
708706f2543Smrg
709706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
710706f2543Smrg    obj = dixLookupPrivate(&rec->target->devPrivates, objectKey);
711706f2543Smrg
712706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode,
713706f2543Smrg			&auditdata);
714706f2543Smrg    if (rc != Success)
715706f2543Smrg	rec->status = rc;
716706f2543Smrg}
717706f2543Smrg
718706f2543Smrgstatic void
719706f2543SmrgSELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
720706f2543Smrg{
721706f2543Smrg    XaceServerAccessRec *rec = calldata;
722706f2543Smrg    SELinuxSubjectRec *subj;
723706f2543Smrg    SELinuxObjectRec *obj;
724706f2543Smrg    SELinuxAuditRec auditdata = { .client = rec->client };
725706f2543Smrg    int rc;
726706f2543Smrg
727706f2543Smrg    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
728706f2543Smrg    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
729706f2543Smrg
730706f2543Smrg    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode,
731706f2543Smrg			&auditdata);
732706f2543Smrg    if (rc != Success)
733706f2543Smrg	rec->status = rc;
734706f2543Smrg}
735706f2543Smrg
736706f2543Smrg
737706f2543Smrg/*
738706f2543Smrg * DIX Callbacks
739706f2543Smrg */
740706f2543Smrg
741706f2543Smrgstatic void
742706f2543SmrgSELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
743706f2543Smrg{
744706f2543Smrg    NewClientInfoRec *pci = calldata;
745706f2543Smrg
746706f2543Smrg    switch (pci->client->clientState) {
747706f2543Smrg    case ClientStateInitial:
748706f2543Smrg	SELinuxLabelClient(pci->client);
749706f2543Smrg	break;
750706f2543Smrg
751706f2543Smrg    default:
752706f2543Smrg	break;
753706f2543Smrg    }
754706f2543Smrg}
755706f2543Smrg
756706f2543Smrgstatic void
757706f2543SmrgSELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
758706f2543Smrg{
759706f2543Smrg    ResourceStateInfoRec *rec = calldata;
760706f2543Smrg    SELinuxSubjectRec *subj;
761706f2543Smrg    SELinuxObjectRec *obj;
762706f2543Smrg    WindowPtr pWin;
763706f2543Smrg
764706f2543Smrg    if (rec->type != RT_WINDOW)
765706f2543Smrg	return;
766706f2543Smrg    if (rec->state != ResourceStateAdding)
767706f2543Smrg	return;
768706f2543Smrg
769706f2543Smrg    pWin = (WindowPtr)rec->value;
770706f2543Smrg    subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
771706f2543Smrg
772706f2543Smrg    if (subj->sid) {
773706f2543Smrg	security_context_t ctx;
774706f2543Smrg	int rc = avc_sid_to_context_raw(subj->sid, &ctx);
775706f2543Smrg	if (rc < 0)
776706f2543Smrg	    FatalError("SELinux: Failed to get security context!\n");
777706f2543Smrg	rc = dixChangeWindowProperty(serverClient,
778706f2543Smrg				     pWin, atom_client_ctx, XA_STRING, 8,
779706f2543Smrg				     PropModeReplace, strlen(ctx), ctx, FALSE);
780706f2543Smrg	if (rc != Success)
781706f2543Smrg	    FatalError("SELinux: Failed to set label property on window!\n");
782706f2543Smrg	freecon(ctx);
783706f2543Smrg    } else
784706f2543Smrg	FatalError("SELinux: Unexpected unlabeled client found\n");
785706f2543Smrg
786706f2543Smrg    obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
787706f2543Smrg
788706f2543Smrg    if (obj->sid) {
789706f2543Smrg	security_context_t ctx;
790706f2543Smrg	int rc = avc_sid_to_context_raw(obj->sid, &ctx);
791706f2543Smrg	if (rc < 0)
792706f2543Smrg	    FatalError("SELinux: Failed to get security context!\n");
793706f2543Smrg	rc = dixChangeWindowProperty(serverClient,
794706f2543Smrg				     pWin, atom_ctx, XA_STRING, 8,
795706f2543Smrg				     PropModeReplace, strlen(ctx), ctx, FALSE);
796706f2543Smrg	if (rc != Success)
797706f2543Smrg	    FatalError("SELinux: Failed to set label property on window!\n");
798706f2543Smrg	freecon(ctx);
799706f2543Smrg    } else
800706f2543Smrg	FatalError("SELinux: Unexpected unlabeled window found\n");
801706f2543Smrg}
802706f2543Smrg
803706f2543Smrg
804706f2543Smrgstatic int netlink_fd;
805706f2543Smrg
806706f2543Smrgstatic void
807706f2543SmrgSELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask)
808706f2543Smrg{
809706f2543Smrg}
810706f2543Smrg
811706f2543Smrgstatic void
812706f2543SmrgSELinuxWakeupHandler(void *data, int err, void *read_mask)
813706f2543Smrg{
814706f2543Smrg    if (FD_ISSET(netlink_fd, (fd_set *)read_mask))
815706f2543Smrg        avc_netlink_check_nb();
816706f2543Smrg}
817706f2543Smrg
818706f2543Smrgvoid
819706f2543SmrgSELinuxFlaskReset(void)
820706f2543Smrg{
821706f2543Smrg    /* Unregister callbacks */
822706f2543Smrg    DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL);
823706f2543Smrg    DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
824706f2543Smrg
825706f2543Smrg    XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
826706f2543Smrg    XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
827706f2543Smrg    XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
828706f2543Smrg    XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
829706f2543Smrg    XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
830706f2543Smrg    XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
831706f2543Smrg    XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
832706f2543Smrg    XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
833706f2543Smrg    XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
834706f2543Smrg    XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
835706f2543Smrg    XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
836706f2543Smrg    XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
837706f2543Smrg
838706f2543Smrg    /* Tear down SELinux stuff */
839706f2543Smrg    audit_close(audit_fd);
840706f2543Smrg    avc_netlink_release_fd();
841706f2543Smrg    RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
842706f2543Smrg                                 NULL);
843706f2543Smrg    RemoveGeneralSocket(netlink_fd);
844706f2543Smrg
845706f2543Smrg    avc_destroy();
846706f2543Smrg}
847706f2543Smrg
848706f2543Smrgvoid
849706f2543SmrgSELinuxFlaskInit(void)
850706f2543Smrg{
851706f2543Smrg    struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *)0 };
852706f2543Smrg    security_context_t ctx;
853706f2543Smrg    int ret = TRUE;
854706f2543Smrg
855706f2543Smrg    switch(selinuxEnforcingState) {
856706f2543Smrg    case SELINUX_MODE_ENFORCING:
857706f2543Smrg	LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n");
858706f2543Smrg	avc_option.value = (char *)1;
859706f2543Smrg	break;
860706f2543Smrg    case SELINUX_MODE_PERMISSIVE:
861706f2543Smrg	LogMessage(X_INFO, "SELinux: Configured in permissive mode\n");
862706f2543Smrg	avc_option.value = (char *)0;
863706f2543Smrg	break;
864706f2543Smrg    default:
865706f2543Smrg	avc_option.type = AVC_OPT_UNUSED;
866706f2543Smrg	break;
867706f2543Smrg    }
868706f2543Smrg
869706f2543Smrg    /* Set up SELinux stuff */
870706f2543Smrg    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog);
871706f2543Smrg    selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit);
872706f2543Smrg
873706f2543Smrg    if (selinux_set_mapping(map) < 0) {
874706f2543Smrg	if (errno == EINVAL) {
875706f2543Smrg	    ErrorF("SELinux: Invalid object class mapping, disabling SELinux support.\n");
876706f2543Smrg	    return;
877706f2543Smrg	}
878706f2543Smrg	FatalError("SELinux: Failed to set up security class mapping\n");
879706f2543Smrg    }
880706f2543Smrg
881706f2543Smrg    if (avc_open(&avc_option, 1) < 0)
882706f2543Smrg	FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n");
883706f2543Smrg
884706f2543Smrg    if (security_get_initial_context_raw("unlabeled", &ctx) < 0)
885706f2543Smrg	FatalError("SELinux: Failed to look up unlabeled context\n");
886706f2543Smrg    if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0)
887706f2543Smrg	FatalError("SELinux: a context_to_SID call failed!\n");
888706f2543Smrg    freecon(ctx);
889706f2543Smrg
890706f2543Smrg    /* Prepare for auditing */
891706f2543Smrg    audit_fd = audit_open();
892706f2543Smrg    if (audit_fd < 0)
893706f2543Smrg	FatalError("SELinux: Failed to open the system audit log\n");
894706f2543Smrg
895706f2543Smrg    /* Allocate private storage */
896706f2543Smrg    if (!dixRegisterPrivateKey(subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) ||
897706f2543Smrg	!dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec)) ||
898706f2543Smrg	!dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec)))
899706f2543Smrg	FatalError("SELinux: Failed to allocate private storage.\n");
900706f2543Smrg
901706f2543Smrg    /* Create atoms for doing window labeling */
902706f2543Smrg    atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
903706f2543Smrg    if (atom_ctx == BAD_RESOURCE)
904706f2543Smrg	FatalError("SELinux: Failed to create atom\n");
905706f2543Smrg    atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
906706f2543Smrg    if (atom_client_ctx == BAD_RESOURCE)
907706f2543Smrg	FatalError("SELinux: Failed to create atom\n");
908706f2543Smrg
909706f2543Smrg    netlink_fd = avc_netlink_acquire_fd();
910706f2543Smrg    AddGeneralSocket(netlink_fd);
911706f2543Smrg    RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
912706f2543Smrg                                   NULL);
913706f2543Smrg
914706f2543Smrg    /* Register callbacks */
915706f2543Smrg    ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
916706f2543Smrg    ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
917706f2543Smrg
918706f2543Smrg    ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
919706f2543Smrg    ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
920706f2543Smrg    ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
921706f2543Smrg    ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
922706f2543Smrg    ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
923706f2543Smrg    ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
924706f2543Smrg    ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
925706f2543Smrg    ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
926706f2543Smrg    ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
927706f2543Smrg    ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
928706f2543Smrg    ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
929706f2543Smrg    ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
930706f2543Smrg    if (!ret)
931706f2543Smrg	FatalError("SELinux: Failed to register one or more callbacks\n");
932706f2543Smrg
933706f2543Smrg    /* Label objects that were created before we could register ourself */
934706f2543Smrg    SELinuxLabelInitial();
935706f2543Smrg}
936