1/************************************************************
2
3Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7this permission notice appear in supporting documentation.  This permission
8notice shall be included in all copies or substantial portions of the
9Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
14AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
18********************************************************/
19
20/*
21 * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc.
22 * All rights reserved.
23 */
24
25#ifdef HAVE_DIX_CONFIG_H
26#include <dix-config.h>
27#endif
28
29#include <sys/socket.h>
30#include <stdio.h>
31#include <stdarg.h>
32
33#include <libaudit.h>
34
35#include <X11/Xatom.h>
36#include "selection.h"
37#include "inputstr.h"
38#include "scrnintstr.h"
39#include "windowstr.h"
40#include "propertyst.h"
41#include "extnsionst.h"
42#include "xacestr.h"
43#include "../os/osdep.h"
44#define _XSELINUX_NEED_FLASK_MAP
45#include "xselinuxint.h"
46
47
48/* structure passed to auditing callback */
49typedef struct {
50    ClientPtr client;	/* client */
51    DeviceIntPtr dev;	/* device */
52    char *command;	/* client's executable path */
53    unsigned id;	/* resource id, if any */
54    int restype;	/* resource type, if any */
55    int event;		/* event type, if any */
56    Atom property;	/* property name, if any */
57    Atom selection;	/* selection name, if any */
58    char *extension;	/* extension name, if any */
59} SELinuxAuditRec;
60
61/* private state keys */
62DevPrivateKeyRec subjectKeyRec;
63DevPrivateKeyRec objectKeyRec;
64DevPrivateKeyRec dataKeyRec;
65
66/* audit file descriptor */
67static int audit_fd;
68
69/* atoms for window label properties */
70static Atom atom_ctx;
71static Atom atom_client_ctx;
72
73/* The unlabeled SID */
74static security_id_t unlabeled_sid;
75
76/* forward declarations */
77static void SELinuxScreen(CallbackListPtr *, pointer, pointer);
78
79/* "true" pointer value for use as callback data */
80static pointer truep = (pointer)1;
81
82
83/*
84 * Performs an SELinux permission check.
85 */
86static int
87SELinuxDoCheck(SELinuxSubjectRec *subj, SELinuxObjectRec *obj,
88	       security_class_t class, Mask mode, SELinuxAuditRec *auditdata)
89{
90    /* serverClient requests OK */
91    if (subj->privileged)
92	return Success;
93
94    auditdata->command = subj->command;
95    errno = 0;
96
97    if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref,
98		     auditdata) < 0) {
99	if (mode == DixUnknownAccess)
100	    return Success; /* DixUnknownAccess requests OK ... for now */
101	if (errno == EACCES)
102	    return BadAccess;
103	ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno);
104	return BadValue;
105    }
106
107    return Success;
108}
109
110/*
111 * Labels a newly connected client.
112 */
113static void
114SELinuxLabelClient(ClientPtr client)
115{
116    int fd = XaceGetConnectionNumber(client);
117    SELinuxSubjectRec *subj;
118    SELinuxObjectRec *obj;
119    security_context_t ctx;
120
121    subj = dixLookupPrivate(&client->devPrivates, subjectKey);
122    obj = dixLookupPrivate(&client->devPrivates, objectKey);
123
124    /* Try to get a context from the socket */
125    if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) {
126	/* Otherwise, fall back to a default context */
127	ctx = SELinuxDefaultClientLabel();
128    }
129
130    /* For local clients, try and determine the executable name */
131    if (XaceIsLocal(client)) {
132	struct ucred creds;
133	socklen_t len = sizeof(creds);
134	char path[PATH_MAX + 1];
135	size_t bytes;
136
137	memset(&creds, 0, sizeof(creds));
138	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0)
139	    goto finish;
140
141	snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid);
142	fd = open(path, O_RDONLY);
143	if (fd < 0)
144	    goto finish;
145
146	bytes = read(fd, path, PATH_MAX + 1);
147	close(fd);
148	if (bytes <= 0)
149	    goto finish;
150
151	strncpy(subj->command, path, COMMAND_LEN - 1);
152    }
153
154finish:
155    /* Get a SID from the context */
156    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
157	FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n",
158		   client->index, ctx);
159
160    obj->sid = subj->sid;
161    freecon(ctx);
162}
163
164/*
165 * Labels initial server objects.
166 */
167static void
168SELinuxLabelInitial(void)
169{
170    int i;
171    XaceScreenAccessRec srec;
172    SELinuxSubjectRec *subj;
173    SELinuxObjectRec *obj;
174    security_context_t ctx;
175    pointer unused;
176
177    /* Do the serverClient */
178    subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
179    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
180    subj->privileged = 1;
181
182    /* Use the context of the X server process for the serverClient */
183    if (getcon_raw(&ctx) < 0)
184	FatalError("SELinux: couldn't get context of X server process\n");
185
186    /* Get a SID from the context */
187    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
188	FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx);
189
190    obj->sid = subj->sid;
191    freecon(ctx);
192
193    srec.client = serverClient;
194    srec.access_mode = DixCreateAccess;
195    srec.status = Success;
196
197    for (i = 0; i < screenInfo.numScreens; i++) {
198	/* Do the screen object */
199	srec.screen = screenInfo.screens[i];
200	SELinuxScreen(NULL, NULL, &srec);
201
202	/* Do the default colormap */
203	dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap,
204			  RT_COLORMAP, serverClient, DixCreateAccess);
205    }
206}
207
208/*
209 * Labels new resource objects.
210 */
211static int
212SELinuxLabelResource(XaceResourceAccessRec *rec, SELinuxSubjectRec *subj,
213		     SELinuxObjectRec *obj, security_class_t class)
214{
215    int offset;
216    security_id_t tsid;
217
218    /* Check for a create context */
219    if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) {
220	obj->sid = subj->win_create_sid;
221	return Success;
222    }
223
224    if (rec->parent)
225	offset = dixLookupPrivateOffset(rec->ptype);
226
227    if (rec->parent && offset >= 0) {
228	/* Use the SID of the parent object in the labeling operation */
229	PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset);
230	SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey);
231	tsid = pobj->sid;
232    } else {
233	/* Use the SID of the subject */
234	tsid = subj->sid;
235    }
236
237    /* Perform a transition to obtain the final SID */
238    if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) {
239	ErrorF("SELinux: a compute_create call failed!\n");
240	return BadValue;
241    }
242
243    return Success;
244}
245
246
247/*
248 * Libselinux Callbacks
249 */
250
251static int
252SELinuxAudit(void *auditdata,
253	     security_class_t class,
254	     char *msgbuf,
255	     size_t msgbufsize)
256{
257    SELinuxAuditRec *audit = auditdata;
258    ClientPtr client = audit->client;
259    char idNum[16];
260    const char *propertyName, *selectionName;
261    int major = -1, minor = -1;
262
263    if (client) {
264	REQUEST(xReq);
265	if (stuff) {
266	    major = stuff->reqType;
267	    minor = MinorOpcodeOfRequest(client);
268	}
269    }
270    if (audit->id)
271	snprintf(idNum, 16, "%x", audit->id);
272
273    propertyName = audit->property ? NameForAtom(audit->property) : NULL;
274    selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
275
276    return snprintf(msgbuf, msgbufsize,
277		    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
278		    (major >= 0) ? "request=" : "",
279		    (major >= 0) ? LookupRequestName(major, minor) : "",
280		    audit->command ? " comm=" : "",
281		    audit->command ? audit->command : "",
282		    audit->dev ? " xdevice=\"" : "",
283		    audit->dev ? audit->dev->name : "",
284		    audit->dev ? "\"" : "",
285		    audit->id ? " resid=" : "",
286		    audit->id ? idNum : "",
287		    audit->restype ? " restype=" : "",
288		    audit->restype ? LookupResourceName(audit->restype) : "",
289		    audit->event ? " event=" : "",
290		    audit->event ? LookupEventName(audit->event & 127) : "",
291		    audit->property ? " property=" : "",
292		    audit->property ? propertyName : "",
293		    audit->selection ? " selection=" : "",
294		    audit->selection ? selectionName : "",
295		    audit->extension ? " extension=" : "",
296		    audit->extension ? audit->extension : "");
297}
298
299static int
300SELinuxLog(int type, const char *fmt, ...)
301{
302    va_list ap;
303    char buf[MAX_AUDIT_MESSAGE_LENGTH];
304    int rc, aut;
305
306    switch (type) {
307    case SELINUX_INFO:
308	aut = AUDIT_USER_MAC_POLICY_LOAD;
309	break;
310    case SELINUX_AVC:
311	aut = AUDIT_USER_AVC;
312	break;
313    default:
314	aut = AUDIT_USER_SELINUX_ERR;
315	break;
316    }
317
318    va_start(ap, fmt);
319    vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap);
320    rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0);
321    va_end(ap);
322    LogMessageVerb(X_WARNING, 0, "%s", buf);
323    return 0;
324}
325
326/*
327 * XACE Callbacks
328 */
329
330static void
331SELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata)
332{
333    XaceDeviceAccessRec *rec = calldata;
334    SELinuxSubjectRec *subj;
335    SELinuxObjectRec *obj;
336    SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev };
337    security_class_t cls;
338    int rc;
339
340    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
341    obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey);
342
343    /* If this is a new object that needs labeling, do it now */
344    if (rec->access_mode & DixCreateAccess) {
345	SELinuxSubjectRec *dsubj;
346	dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
347
348	if (subj->dev_create_sid) {
349	    /* Label the device with the create context */
350	    obj->sid = subj->dev_create_sid;
351	    dsubj->sid = subj->dev_create_sid;
352	} else {
353	    /* Label the device directly with the process SID */
354	    obj->sid = subj->sid;
355	    dsubj->sid = subj->sid;
356	}
357    }
358
359    cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD;
360    rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata);
361    if (rc != Success)
362	rec->status = rc;
363}
364
365static void
366SELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata)
367{
368    XaceSendAccessRec *rec = calldata;
369    SELinuxSubjectRec *subj;
370    SELinuxObjectRec *obj, ev_sid;
371    SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev };
372    security_class_t class;
373    int rc, i, type;
374
375    if (rec->dev)
376	subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
377    else
378	subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
379
380    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
381
382    /* Check send permission on window */
383    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess,
384			&auditdata);
385    if (rc != Success)
386	goto err;
387
388    /* Check send permission on specific event types */
389    for (i = 0; i < rec->count; i++) {
390	type = rec->events[i].u.u.type;
391	class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
392
393	rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
394	if (rc != Success)
395	    goto err;
396
397	auditdata.event = type;
398	rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata);
399	if (rc != Success)
400	    goto err;
401    }
402    return;
403err:
404    rec->status = rc;
405}
406
407static void
408SELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata)
409{
410    XaceReceiveAccessRec *rec = calldata;
411    SELinuxSubjectRec *subj;
412    SELinuxObjectRec *obj, ev_sid;
413    SELinuxAuditRec auditdata = { .client = NULL };
414    security_class_t class;
415    int rc, i, type;
416
417    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
418    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
419
420    /* Check receive permission on window */
421    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess,
422			&auditdata);
423    if (rc != Success)
424	goto err;
425
426    /* Check receive permission on specific event types */
427    for (i = 0; i < rec->count; i++) {
428	type = rec->events[i].u.u.type;
429	class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
430
431	rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
432	if (rc != Success)
433	    goto err;
434
435	auditdata.event = type;
436	rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata);
437	if (rc != Success)
438	    goto err;
439    }
440    return;
441err:
442    rec->status = rc;
443}
444
445static void
446SELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata)
447{
448    XaceExtAccessRec *rec = calldata;
449    SELinuxSubjectRec *subj, *serv;
450    SELinuxObjectRec *obj;
451    SELinuxAuditRec auditdata = { .client = rec->client };
452    int rc;
453
454    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
455    obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey);
456
457    /* If this is a new object that needs labeling, do it now */
458    /* XXX there should be a separate callback for this */
459    if (obj->sid == NULL) {
460	security_id_t sid;
461
462	serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
463	rc = SELinuxExtensionToSID(rec->ext->name, &sid);
464	if (rc != Success) {
465	    rec->status = rc;
466	    return;
467	}
468
469	/* Perform a transition to obtain the final SID */
470	if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
471			       &obj->sid) < 0) {
472	    ErrorF("SELinux: a SID transition call failed!\n");
473	    rec->status = BadValue;
474	    return;
475	}
476    }
477
478    /* Perform the security check */
479    auditdata.extension = rec->ext->name;
480    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode,
481			&auditdata);
482    if (rc != Success)
483	rec->status = rc;
484}
485
486static void
487SELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata)
488{
489    XaceSelectionAccessRec *rec = calldata;
490    SELinuxSubjectRec *subj;
491    SELinuxObjectRec *obj, *data;
492    Selection *pSel = *rec->ppSel;
493    Atom name = pSel->selection;
494    Mask access_mode = rec->access_mode;
495    SELinuxAuditRec auditdata = { .client = rec->client, .selection = name };
496    security_id_t tsid;
497    int rc;
498
499    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
500    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
501
502    /* If this is a new object that needs labeling, do it now */
503    if (access_mode & DixCreateAccess) {
504	rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly);
505	if (rc != Success)
506	    obj->sid = unlabeled_sid;
507	access_mode = DixSetAttrAccess;
508    }
509    /* If this is a polyinstantiated object, find the right instance */
510    else if (obj->poly) {
511	rc = SELinuxSelectionToSID(name, subj, &tsid, NULL);
512	if (rc != Success) {
513	    rec->status = rc;
514	    return;
515	}
516	while (pSel->selection != name || obj->sid != tsid) {
517	    if ((pSel = pSel->next) == NULL)
518		break;
519	    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
520	}
521
522	if (pSel)
523	    *rec->ppSel = pSel;
524	else {
525	    rec->status = BadMatch;
526	    return;
527	}
528    }
529
530    /* Perform the security check */
531    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode,
532			&auditdata);
533    if (rc != Success)
534	rec->status = rc;
535
536    /* Label the content (advisory only) */
537    if (access_mode & DixSetAttrAccess) {
538	data = dixLookupPrivate(&pSel->devPrivates, dataKey);
539	if (subj->sel_create_sid)
540	    data->sid = subj->sel_create_sid;
541	else
542	    data->sid = obj->sid;
543    }
544}
545
546static void
547SELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata)
548{
549    XacePropertyAccessRec *rec = calldata;
550    SELinuxSubjectRec *subj;
551    SELinuxObjectRec *obj, *data;
552    PropertyPtr pProp = *rec->ppProp;
553    Atom name = pProp->propertyName;
554    SELinuxAuditRec auditdata = { .client = rec->client, .property = name };
555    security_id_t tsid;
556    int rc;
557
558    /* Don't care about the new content check */
559    if (rec->access_mode & DixPostAccess)
560	return;
561
562    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
563    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
564
565    /* If this is a new object that needs labeling, do it now */
566    if (rec->access_mode & DixCreateAccess) {
567	rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly);
568	if (rc != Success) {
569	    rec->status = rc;
570	    return;
571	}
572    }
573    /* If this is a polyinstantiated object, find the right instance */
574    else if (obj->poly) {
575	rc = SELinuxPropertyToSID(name, subj, &tsid, NULL);
576	if (rc != Success) {
577	    rec->status = rc;
578	    return;
579	}
580	while (pProp->propertyName != name || obj->sid != tsid) {
581	    if ((pProp = pProp->next) == NULL)
582		break;
583	    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
584	}
585
586	if (pProp)
587	    *rec->ppProp = pProp;
588	else {
589	    rec->status = BadMatch;
590	    return;
591	}
592    }
593
594    /* Perform the security check */
595    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode,
596			&auditdata);
597    if (rc != Success)
598	rec->status = rc;
599
600    /* Label the content (advisory only) */
601    if (rec->access_mode & DixWriteAccess) {
602	data = dixLookupPrivate(&pProp->devPrivates, dataKey);
603	if (subj->prp_create_sid)
604	    data->sid = subj->prp_create_sid;
605	else
606	    data->sid = obj->sid;
607    }
608}
609
610static void
611SELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata)
612{
613    XaceResourceAccessRec *rec = calldata;
614    SELinuxSubjectRec *subj;
615    SELinuxObjectRec *obj;
616    SELinuxAuditRec auditdata = { .client = rec->client };
617    Mask access_mode = rec->access_mode;
618    PrivateRec **privatePtr;
619    security_class_t class;
620    int rc, offset;
621
622    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
623
624    /* Determine if the resource object has a devPrivates field */
625    offset = dixLookupPrivateOffset(rec->rtype);
626    if (offset < 0) {
627	/* No: use the SID of the owning client */
628	class = SECCLASS_X_RESOURCE;
629	privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
630	obj = dixLookupPrivate(privatePtr, objectKey);
631    } else {
632	/* Yes: use the SID from the resource object itself */
633	class = SELinuxTypeToClass(rec->rtype);
634	privatePtr = DEVPRIV_AT(rec->res, offset);
635	obj = dixLookupPrivate(privatePtr, objectKey);
636    }
637
638    /* If this is a new object that needs labeling, do it now */
639    if (access_mode & DixCreateAccess && offset >= 0) {
640	rc = SELinuxLabelResource(rec, subj, obj, class);
641	if (rc != Success) {
642	    rec->status = rc;
643	    return;
644	}
645    }
646
647    /* Collapse generic resource permissions down to read/write */
648    if (class == SECCLASS_X_RESOURCE) {
649	access_mode = !!(rec->access_mode & SELinuxReadMask); /* rd */
650	access_mode |= !!(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */
651    }
652
653    /* Perform the security check */
654    auditdata.restype = rec->rtype;
655    auditdata.id = rec->id;
656    rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata);
657    if (rc != Success)
658	rec->status = rc;
659
660    /* Perform the background none check on windows */
661    if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) {
662	rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata);
663	if (rc != Success)
664	    ((WindowPtr)rec->res)->forcedBG = TRUE;
665    }
666}
667
668static void
669SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata)
670{
671    XaceScreenAccessRec *rec = calldata;
672    SELinuxSubjectRec *subj;
673    SELinuxObjectRec *obj;
674    SELinuxAuditRec auditdata = { .client = rec->client };
675    Mask access_mode = rec->access_mode;
676    int rc;
677
678    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
679    obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey);
680
681    /* If this is a new object that needs labeling, do it now */
682    if (access_mode & DixCreateAccess) {
683	/* Perform a transition to obtain the final SID */
684	if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
685			       &obj->sid) < 0) {
686	    ErrorF("SELinux: a compute_create call failed!\n");
687	    rec->status = BadValue;
688	    return;
689	}
690    }
691
692    if (is_saver)
693	access_mode <<= 2;
694
695    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata);
696    if (rc != Success)
697	rec->status = rc;
698}
699
700static void
701SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata)
702{
703    XaceClientAccessRec *rec = calldata;
704    SELinuxSubjectRec *subj;
705    SELinuxObjectRec *obj;
706    SELinuxAuditRec auditdata = { .client = rec->client };
707    int rc;
708
709    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
710    obj = dixLookupPrivate(&rec->target->devPrivates, objectKey);
711
712    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode,
713			&auditdata);
714    if (rc != Success)
715	rec->status = rc;
716}
717
718static void
719SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
720{
721    XaceServerAccessRec *rec = calldata;
722    SELinuxSubjectRec *subj;
723    SELinuxObjectRec *obj;
724    SELinuxAuditRec auditdata = { .client = rec->client };
725    int rc;
726
727    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
728    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
729
730    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode,
731			&auditdata);
732    if (rc != Success)
733	rec->status = rc;
734}
735
736
737/*
738 * DIX Callbacks
739 */
740
741static void
742SELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
743{
744    NewClientInfoRec *pci = calldata;
745
746    switch (pci->client->clientState) {
747    case ClientStateInitial:
748	SELinuxLabelClient(pci->client);
749	break;
750
751    default:
752	break;
753    }
754}
755
756static void
757SELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
758{
759    ResourceStateInfoRec *rec = calldata;
760    SELinuxSubjectRec *subj;
761    SELinuxObjectRec *obj;
762    WindowPtr pWin;
763
764    if (rec->type != RT_WINDOW)
765	return;
766    if (rec->state != ResourceStateAdding)
767	return;
768
769    pWin = (WindowPtr)rec->value;
770    subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
771
772    if (subj->sid) {
773	security_context_t ctx;
774	int rc = avc_sid_to_context_raw(subj->sid, &ctx);
775	if (rc < 0)
776	    FatalError("SELinux: Failed to get security context!\n");
777	rc = dixChangeWindowProperty(serverClient,
778				     pWin, atom_client_ctx, XA_STRING, 8,
779				     PropModeReplace, strlen(ctx), ctx, FALSE);
780	if (rc != Success)
781	    FatalError("SELinux: Failed to set label property on window!\n");
782	freecon(ctx);
783    } else
784	FatalError("SELinux: Unexpected unlabeled client found\n");
785
786    obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
787
788    if (obj->sid) {
789	security_context_t ctx;
790	int rc = avc_sid_to_context_raw(obj->sid, &ctx);
791	if (rc < 0)
792	    FatalError("SELinux: Failed to get security context!\n");
793	rc = dixChangeWindowProperty(serverClient,
794				     pWin, atom_ctx, XA_STRING, 8,
795				     PropModeReplace, strlen(ctx), ctx, FALSE);
796	if (rc != Success)
797	    FatalError("SELinux: Failed to set label property on window!\n");
798	freecon(ctx);
799    } else
800	FatalError("SELinux: Unexpected unlabeled window found\n");
801}
802
803
804static int netlink_fd;
805
806static void
807SELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask)
808{
809}
810
811static void
812SELinuxWakeupHandler(void *data, int err, void *read_mask)
813{
814    if (FD_ISSET(netlink_fd, (fd_set *)read_mask))
815        avc_netlink_check_nb();
816}
817
818void
819SELinuxFlaskReset(void)
820{
821    /* Unregister callbacks */
822    DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL);
823    DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
824
825    XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
826    XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
827    XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
828    XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
829    XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
830    XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
831    XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
832    XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
833    XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
834    XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
835    XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
836    XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
837
838    /* Tear down SELinux stuff */
839    audit_close(audit_fd);
840    avc_netlink_release_fd();
841    RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
842                                 NULL);
843    RemoveGeneralSocket(netlink_fd);
844
845    avc_destroy();
846}
847
848void
849SELinuxFlaskInit(void)
850{
851    struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *)0 };
852    security_context_t ctx;
853    int ret = TRUE;
854
855    switch(selinuxEnforcingState) {
856    case SELINUX_MODE_ENFORCING:
857	LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n");
858	avc_option.value = (char *)1;
859	break;
860    case SELINUX_MODE_PERMISSIVE:
861	LogMessage(X_INFO, "SELinux: Configured in permissive mode\n");
862	avc_option.value = (char *)0;
863	break;
864    default:
865	avc_option.type = AVC_OPT_UNUSED;
866	break;
867    }
868
869    /* Set up SELinux stuff */
870    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog);
871    selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit);
872
873    if (selinux_set_mapping(map) < 0) {
874	if (errno == EINVAL) {
875	    ErrorF("SELinux: Invalid object class mapping, disabling SELinux support.\n");
876	    return;
877	}
878	FatalError("SELinux: Failed to set up security class mapping\n");
879    }
880
881    if (avc_open(&avc_option, 1) < 0)
882	FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n");
883
884    if (security_get_initial_context_raw("unlabeled", &ctx) < 0)
885	FatalError("SELinux: Failed to look up unlabeled context\n");
886    if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0)
887	FatalError("SELinux: a context_to_SID call failed!\n");
888    freecon(ctx);
889
890    /* Prepare for auditing */
891    audit_fd = audit_open();
892    if (audit_fd < 0)
893	FatalError("SELinux: Failed to open the system audit log\n");
894
895    /* Allocate private storage */
896    if (!dixRegisterPrivateKey(subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) ||
897	!dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec)) ||
898	!dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec)))
899	FatalError("SELinux: Failed to allocate private storage.\n");
900
901    /* Create atoms for doing window labeling */
902    atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
903    if (atom_ctx == BAD_RESOURCE)
904	FatalError("SELinux: Failed to create atom\n");
905    atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
906    if (atom_client_ctx == BAD_RESOURCE)
907	FatalError("SELinux: Failed to create atom\n");
908
909    netlink_fd = avc_netlink_acquire_fd();
910    AddGeneralSocket(netlink_fd);
911    RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
912                                   NULL);
913
914    /* Register callbacks */
915    ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
916    ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
917
918    ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
919    ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
920    ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
921    ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
922    ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
923    ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
924    ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
925    ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
926    ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
927    ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
928    ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
929    ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
930    if (!ret)
931	FatalError("SELinux: Failed to register one or more callbacks\n");
932
933    /* Label objects that were created before we could register ourself */
934    SELinuxLabelInitial();
935}
936