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 "client.h"
44#define _XSELINUX_NEED_FLASK_MAP
45#include "xselinuxint.h"
46
47/* structure passed to auditing callback */
48typedef struct {
49    ClientPtr client;           /* client */
50    DeviceIntPtr dev;           /* device */
51    char *command;              /* client's executable path */
52    unsigned id;                /* resource id, if any */
53    int restype;                /* resource type, if any */
54    int event;                  /* event type, if any */
55    Atom property;              /* property name, if any */
56    Atom selection;             /* selection name, if any */
57    char *extension;            /* extension name, if any */
58} SELinuxAuditRec;
59
60/* private state keys */
61DevPrivateKeyRec subjectKeyRec;
62DevPrivateKeyRec objectKeyRec;
63DevPrivateKeyRec dataKeyRec;
64
65/* audit file descriptor */
66static int audit_fd;
67
68/* atoms for window label properties */
69static Atom atom_ctx;
70static Atom atom_client_ctx;
71
72/* The unlabeled SID */
73static security_id_t unlabeled_sid;
74
75/* forward declarations */
76static void SELinuxScreen(CallbackListPtr *, void *, void *);
77
78/* "true" pointer value for use as callback data */
79static void *truep = (void *) 1;
80
81/*
82 * Performs an SELinux permission check.
83 */
84static int
85SELinuxDoCheck(SELinuxSubjectRec * subj, SELinuxObjectRec * obj,
86               security_class_t class, Mask mode, SELinuxAuditRec * auditdata)
87{
88    /* serverClient requests OK */
89    if (subj->privileged)
90        return Success;
91
92    auditdata->command = subj->command;
93    errno = 0;
94
95    if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref,
96                     auditdata) < 0) {
97        if (mode == DixUnknownAccess)
98            return Success;     /* DixUnknownAccess requests OK ... for now */
99        if (errno == EACCES)
100            return BadAccess;
101        ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno);
102        return BadValue;
103    }
104
105    return Success;
106}
107
108/*
109 * Labels a newly connected client.
110 */
111static void
112SELinuxLabelClient(ClientPtr client)
113{
114    int fd = XaceGetConnectionNumber(client);
115    SELinuxSubjectRec *subj;
116    SELinuxObjectRec *obj;
117    char *ctx;
118
119    subj = dixLookupPrivate(&client->devPrivates, subjectKey);
120    obj = dixLookupPrivate(&client->devPrivates, objectKey);
121
122    /* Try to get a context from the socket */
123    if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) {
124        /* Otherwise, fall back to a default context */
125        ctx = SELinuxDefaultClientLabel();
126    }
127
128    /* For local clients, try and determine the executable name */
129    if (XaceIsLocal(client)) {
130        /* Get cached command name if CLIENTIDS is enabled. */
131        const char *cmdname = GetClientCmdName(client);
132        Bool cached = (cmdname != NULL);
133
134        /* If CLIENTIDS is disabled, figure out the command name from
135         * scratch. */
136        if (!cmdname) {
137            pid_t pid = DetermineClientPid(client);
138
139            if (pid != -1)
140                DetermineClientCmd(pid, &cmdname, NULL);
141        }
142
143        if (!cmdname)
144            goto finish;
145
146        strncpy(subj->command, cmdname, COMMAND_LEN - 1);
147
148        if (!cached)
149            free((void *) cmdname);     /* const char * */
150    }
151
152 finish:
153    /* Get a SID from the context */
154    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
155        FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n",
156                   client->index, ctx);
157
158    obj->sid = subj->sid;
159    freecon(ctx);
160}
161
162/*
163 * Labels initial server objects.
164 */
165static void
166SELinuxLabelInitial(void)
167{
168    int i;
169    XaceScreenAccessRec srec;
170    SELinuxSubjectRec *subj;
171    SELinuxObjectRec *obj;
172    char *ctx;
173    void *unused;
174
175    /* Do the serverClient */
176    subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
177    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
178    subj->privileged = 1;
179
180    /* Use the context of the X server process for the serverClient */
181    if (getcon_raw(&ctx) < 0)
182        FatalError("SELinux: couldn't get context of X server process\n");
183
184    /* Get a SID from the context */
185    if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
186        FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx);
187
188    obj->sid = subj->sid;
189    freecon(ctx);
190
191    srec.client = serverClient;
192    srec.access_mode = DixCreateAccess;
193    srec.status = Success;
194
195    for (i = 0; i < screenInfo.numScreens; i++) {
196        /* Do the screen object */
197        srec.screen = screenInfo.screens[i];
198        SELinuxScreen(NULL, NULL, &srec);
199
200        /* Do the default colormap */
201        dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap,
202                                RT_COLORMAP, serverClient, DixCreateAccess);
203    }
204}
205
206/*
207 * Labels new resource objects.
208 */
209static int
210SELinuxLabelResource(XaceResourceAccessRec * rec, SELinuxSubjectRec * subj,
211                     SELinuxObjectRec * obj, security_class_t class)
212{
213    int offset;
214    security_id_t tsid;
215
216    /* Check for a create context */
217    if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) {
218        obj->sid = subj->win_create_sid;
219        return Success;
220    }
221
222    if (rec->parent)
223        offset = dixLookupPrivateOffset(rec->ptype);
224
225    if (rec->parent && offset >= 0) {
226        /* Use the SID of the parent object in the labeling operation */
227        PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset);
228        SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey);
229
230        tsid = pobj->sid;
231    }
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 * Libselinux Callbacks
248 */
249
250static int
251SELinuxAudit(void *auditdata,
252             security_class_t class, char *msgbuf, size_t msgbufsize)
253{
254    SELinuxAuditRec *audit = auditdata;
255    ClientPtr client = audit->client;
256    char idNum[16];
257    const char *propertyName, *selectionName;
258    int major = -1, minor = -1;
259
260    if (client) {
261        REQUEST(xReq);
262        if (stuff) {
263            major = client->majorOp;
264            minor = client->minorOp;
265        }
266    }
267    if (audit->id)
268        snprintf(idNum, 16, "%x", audit->id);
269
270    propertyName = audit->property ? NameForAtom(audit->property) : NULL;
271    selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
272
273    return snprintf(msgbuf, msgbufsize,
274                    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
275                    (major >= 0) ? "request=" : "",
276                    (major >= 0) ? LookupRequestName(major, minor) : "",
277                    audit->command ? " comm=" : "",
278                    audit->command ? audit->command : "",
279                    audit->dev ? " xdevice=\"" : "",
280                    audit->dev ? audit->dev->name : "",
281                    audit->dev ? "\"" : "",
282                    audit->id ? " resid=" : "",
283                    audit->id ? idNum : "",
284                    audit->restype ? " restype=" : "",
285                    audit->restype ? LookupResourceName(audit->restype) : "",
286                    audit->event ? " event=" : "",
287                    audit->event ? LookupEventName(audit->event & 127) : "",
288                    audit->property ? " property=" : "",
289                    audit->property ? propertyName : "",
290                    audit->selection ? " selection=" : "",
291                    audit->selection ? selectionName : "",
292                    audit->extension ? " extension=" : "",
293                    audit->extension ? audit->extension : "");
294}
295
296static int
297SELinuxLog(int type, const char *fmt, ...) _X_ATTRIBUTE_PRINTF(2, 3);
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    (void) rc;
322    va_end(ap);
323    LogMessageVerb(X_WARNING, 0, "%s", buf);
324    return 0;
325}
326
327/*
328 * XACE Callbacks
329 */
330
331static void
332SELinuxDevice(CallbackListPtr *pcbl, void *unused, void *calldata)
333{
334    XaceDeviceAccessRec *rec = calldata;
335    SELinuxSubjectRec *subj;
336    SELinuxObjectRec *obj;
337    SELinuxAuditRec auditdata = {.client = rec->client,.dev = rec->dev };
338    security_class_t cls;
339    int rc;
340
341    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
342    obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey);
343
344    /* If this is a new object that needs labeling, do it now */
345    if (rec->access_mode & DixCreateAccess) {
346        SELinuxSubjectRec *dsubj;
347
348        dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
349
350        if (subj->dev_create_sid) {
351            /* Label the device with the create context */
352            obj->sid = subj->dev_create_sid;
353            dsubj->sid = subj->dev_create_sid;
354        }
355        else {
356            /* Label the device directly with the process SID */
357            obj->sid = subj->sid;
358            dsubj->sid = subj->sid;
359        }
360    }
361
362    cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD;
363    rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata);
364    if (rc != Success)
365        rec->status = rc;
366}
367
368static void
369SELinuxSend(CallbackListPtr *pcbl, void *unused, void *calldata)
370{
371    XaceSendAccessRec *rec = calldata;
372    SELinuxSubjectRec *subj;
373    SELinuxObjectRec *obj, ev_sid;
374    SELinuxAuditRec auditdata = {.client = rec->client,.dev = rec->dev };
375    security_class_t class;
376    int rc, i, type;
377
378    if (rec->dev)
379        subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
380    else
381        subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
382
383    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
384
385    /* Check send permission on window */
386    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess,
387                        &auditdata);
388    if (rc != Success)
389        goto err;
390
391    /* Check send permission on specific event types */
392    for (i = 0; i < rec->count; i++) {
393        type = rec->events[i].u.u.type;
394        class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
395
396        rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
397        if (rc != Success)
398            goto err;
399
400        auditdata.event = type;
401        rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata);
402        if (rc != Success)
403            goto err;
404    }
405    return;
406 err:
407    rec->status = rc;
408}
409
410static void
411SELinuxReceive(CallbackListPtr *pcbl, void *unused, void *calldata)
412{
413    XaceReceiveAccessRec *rec = calldata;
414    SELinuxSubjectRec *subj;
415    SELinuxObjectRec *obj, ev_sid;
416    SELinuxAuditRec auditdata = {.client = NULL };
417    security_class_t class;
418    int rc, i, type;
419
420    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
421    obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
422
423    /* Check receive permission on window */
424    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess,
425                        &auditdata);
426    if (rc != Success)
427        goto err;
428
429    /* Check receive permission on specific event types */
430    for (i = 0; i < rec->count; i++) {
431        type = rec->events[i].u.u.type;
432        class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
433
434        rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
435        if (rc != Success)
436            goto err;
437
438        auditdata.event = type;
439        rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata);
440        if (rc != Success)
441            goto err;
442    }
443    return;
444 err:
445    rec->status = rc;
446}
447
448static void
449SELinuxExtension(CallbackListPtr *pcbl, void *unused, void *calldata)
450{
451    XaceExtAccessRec *rec = calldata;
452    SELinuxSubjectRec *subj, *serv;
453    SELinuxObjectRec *obj;
454    SELinuxAuditRec auditdata = {.client = rec->client };
455    int rc;
456
457    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
458    obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey);
459
460    /* If this is a new object that needs labeling, do it now */
461    /* XXX there should be a separate callback for this */
462    if (obj->sid == NULL) {
463        security_id_t sid;
464
465        serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
466        rc = SELinuxExtensionToSID(rec->ext->name, &sid);
467        if (rc != Success) {
468            rec->status = rc;
469            return;
470        }
471
472        /* Perform a transition to obtain the final SID */
473        if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
474                               &obj->sid) < 0) {
475            ErrorF("SELinux: a SID transition call failed!\n");
476            rec->status = BadValue;
477            return;
478        }
479    }
480
481    /* Perform the security check */
482    auditdata.extension = (char *) rec->ext->name;
483    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode,
484                        &auditdata);
485    if (rc != Success)
486        rec->status = rc;
487}
488
489static void
490SELinuxSelection(CallbackListPtr *pcbl, void *unused, void *calldata)
491{
492    XaceSelectionAccessRec *rec = calldata;
493    SELinuxSubjectRec *subj;
494    SELinuxObjectRec *obj, *data;
495    Selection *pSel = *rec->ppSel;
496    Atom name = pSel->selection;
497    Mask access_mode = rec->access_mode;
498    SELinuxAuditRec auditdata = {.client = rec->client,.selection = name };
499    security_id_t tsid;
500    int rc;
501
502    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
503    obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
504
505    /* If this is a new object that needs labeling, do it now */
506    if (access_mode & DixCreateAccess) {
507        rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly);
508        if (rc != Success)
509            obj->sid = unlabeled_sid;
510        access_mode = DixSetAttrAccess;
511    }
512    /* If this is a polyinstantiated object, find the right instance */
513    else if (obj->poly) {
514        rc = SELinuxSelectionToSID(name, subj, &tsid, NULL);
515        if (rc != Success) {
516            rec->status = rc;
517            return;
518        }
519        while (pSel->selection != name || obj->sid != tsid) {
520            if ((pSel = pSel->next) == NULL)
521                break;
522            obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
523        }
524
525        if (pSel)
526            *rec->ppSel = pSel;
527        else {
528            rec->status = BadMatch;
529            return;
530        }
531    }
532
533    /* Perform the security check */
534    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode,
535                        &auditdata);
536    if (rc != Success)
537        rec->status = rc;
538
539    /* Label the content (advisory only) */
540    if (access_mode & DixSetAttrAccess) {
541        data = dixLookupPrivate(&pSel->devPrivates, dataKey);
542        if (subj->sel_create_sid)
543            data->sid = subj->sel_create_sid;
544        else
545            data->sid = obj->sid;
546    }
547}
548
549static void
550SELinuxProperty(CallbackListPtr *pcbl, void *unused, void *calldata)
551{
552    XacePropertyAccessRec *rec = calldata;
553    SELinuxSubjectRec *subj;
554    SELinuxObjectRec *obj, *data;
555    PropertyPtr pProp = *rec->ppProp;
556    Atom name = pProp->propertyName;
557    SELinuxAuditRec auditdata = {.client = rec->client,.property = name };
558    security_id_t tsid;
559    int rc;
560
561    /* Don't care about the new content check */
562    if (rec->access_mode & DixPostAccess)
563        return;
564
565    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
566    obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
567
568    /* If this is a new object that needs labeling, do it now */
569    if (rec->access_mode & DixCreateAccess) {
570        rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly);
571        if (rc != Success) {
572            rec->status = rc;
573            return;
574        }
575    }
576    /* If this is a polyinstantiated object, find the right instance */
577    else if (obj->poly) {
578        rc = SELinuxPropertyToSID(name, subj, &tsid, NULL);
579        if (rc != Success) {
580            rec->status = rc;
581            return;
582        }
583        while (pProp->propertyName != name || obj->sid != tsid) {
584            if ((pProp = pProp->next) == NULL)
585                break;
586            obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
587        }
588
589        if (pProp)
590            *rec->ppProp = pProp;
591        else {
592            rec->status = BadMatch;
593            return;
594        }
595    }
596
597    /* Perform the security check */
598    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode,
599                        &auditdata);
600    if (rc != Success)
601        rec->status = rc;
602
603    /* Label the content (advisory only) */
604    if (rec->access_mode & DixWriteAccess) {
605        data = dixLookupPrivate(&pProp->devPrivates, dataKey);
606        if (subj->prp_create_sid)
607            data->sid = subj->prp_create_sid;
608        else
609            data->sid = obj->sid;
610    }
611}
612
613static void
614SELinuxResource(CallbackListPtr *pcbl, void *unused, void *calldata)
615{
616    XaceResourceAccessRec *rec = calldata;
617    SELinuxSubjectRec *subj;
618    SELinuxObjectRec *obj;
619    SELinuxAuditRec auditdata = {.client = rec->client };
620    Mask access_mode = rec->access_mode;
621    PrivateRec **privatePtr;
622    security_class_t class;
623    int rc, offset;
624
625    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
626
627    /* Determine if the resource object has a devPrivates field */
628    offset = dixLookupPrivateOffset(rec->rtype);
629    if (offset < 0) {
630        /* No: use the SID of the owning client */
631        class = SECCLASS_X_RESOURCE;
632        privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
633        obj = dixLookupPrivate(privatePtr, objectKey);
634    }
635    else {
636        /* Yes: use the SID from the resource object itself */
637        class = SELinuxTypeToClass(rec->rtype);
638        privatePtr = DEVPRIV_AT(rec->res, offset);
639        obj = dixLookupPrivate(privatePtr, objectKey);
640    }
641
642    /* If this is a new object that needs labeling, do it now */
643    if (access_mode & DixCreateAccess && offset >= 0) {
644        rc = SELinuxLabelResource(rec, subj, obj, class);
645        if (rc != Success) {
646            rec->status = rc;
647            return;
648        }
649    }
650
651    /* Collapse generic resource permissions down to read/write */
652    if (class == SECCLASS_X_RESOURCE) {
653        access_mode = ! !(rec->access_mode & SELinuxReadMask);  /* rd */
654        access_mode |= ! !(rec->access_mode & ~SELinuxReadMask) << 1;   /* wr */
655    }
656
657    /* Perform the security check */
658    auditdata.restype = rec->rtype;
659    auditdata.id = rec->id;
660    rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata);
661    if (rc != Success)
662        rec->status = rc;
663
664    /* Perform the background none check on windows */
665    if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) {
666        rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata);
667        if (rc != Success)
668            ((WindowPtr) rec->res)->forcedBG = TRUE;
669    }
670}
671
672static void
673SELinuxScreen(CallbackListPtr *pcbl, void *is_saver, void *calldata)
674{
675    XaceScreenAccessRec *rec = calldata;
676    SELinuxSubjectRec *subj;
677    SELinuxObjectRec *obj;
678    SELinuxAuditRec auditdata = {.client = rec->client };
679    Mask access_mode = rec->access_mode;
680    int rc;
681
682    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
683    obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey);
684
685    /* If this is a new object that needs labeling, do it now */
686    if (access_mode & DixCreateAccess) {
687        /* Perform a transition to obtain the final SID */
688        if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
689                               &obj->sid) < 0) {
690            ErrorF("SELinux: a compute_create call failed!\n");
691            rec->status = BadValue;
692            return;
693        }
694    }
695
696    if (is_saver)
697        access_mode <<= 2;
698
699    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata);
700    if (rc != Success)
701        rec->status = rc;
702}
703
704static void
705SELinuxClient(CallbackListPtr *pcbl, void *unused, void *calldata)
706{
707    XaceClientAccessRec *rec = calldata;
708    SELinuxSubjectRec *subj;
709    SELinuxObjectRec *obj;
710    SELinuxAuditRec auditdata = {.client = rec->client };
711    int rc;
712
713    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
714    obj = dixLookupPrivate(&rec->target->devPrivates, objectKey);
715
716    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode,
717                        &auditdata);
718    if (rc != Success)
719        rec->status = rc;
720}
721
722static void
723SELinuxServer(CallbackListPtr *pcbl, void *unused, void *calldata)
724{
725    XaceServerAccessRec *rec = calldata;
726    SELinuxSubjectRec *subj;
727    SELinuxObjectRec *obj;
728    SELinuxAuditRec auditdata = {.client = rec->client };
729    int rc;
730
731    subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
732    obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
733
734    rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode,
735                        &auditdata);
736    if (rc != Success)
737        rec->status = rc;
738}
739
740/*
741 * DIX Callbacks
742 */
743
744static void
745SELinuxClientState(CallbackListPtr *pcbl, void *unused, void *calldata)
746{
747    NewClientInfoRec *pci = calldata;
748
749    switch (pci->client->clientState) {
750    case ClientStateInitial:
751        SELinuxLabelClient(pci->client);
752        break;
753
754    default:
755        break;
756    }
757}
758
759static void
760SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
761{
762    ResourceStateInfoRec *rec = calldata;
763    SELinuxSubjectRec *subj;
764    SELinuxObjectRec *obj;
765    WindowPtr pWin;
766
767    if (rec->type != RT_WINDOW)
768        return;
769    if (rec->state != ResourceStateAdding)
770        return;
771
772    pWin = (WindowPtr) rec->value;
773    subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
774
775    if (subj->sid) {
776        char *ctx;
777        int rc = avc_sid_to_context_raw(subj->sid, &ctx);
778
779        if (rc < 0)
780            FatalError("SELinux: Failed to get security context!\n");
781        rc = dixChangeWindowProperty(serverClient,
782                                     pWin, atom_client_ctx, XA_STRING, 8,
783                                     PropModeReplace, strlen(ctx), ctx, FALSE);
784        if (rc != Success)
785            FatalError("SELinux: Failed to set label property on window!\n");
786        freecon(ctx);
787    }
788    else
789        FatalError("SELinux: Unexpected unlabeled client found\n");
790
791    obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
792
793    if (obj->sid) {
794        char *ctx;
795        int rc = avc_sid_to_context_raw(obj->sid, &ctx);
796
797        if (rc < 0)
798            FatalError("SELinux: Failed to get security context!\n");
799        rc = dixChangeWindowProperty(serverClient,
800                                     pWin, atom_ctx, XA_STRING, 8,
801                                     PropModeReplace, strlen(ctx), ctx, FALSE);
802        if (rc != Success)
803            FatalError("SELinux: Failed to set label property on window!\n");
804        freecon(ctx);
805    }
806    else
807        FatalError("SELinux: Unexpected unlabeled window found\n");
808}
809
810static int netlink_fd;
811
812static void
813SELinuxNetlinkNotify(int fd, int ready, void *data)
814{
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    RemoveNotifyFd(netlink_fd);
842
843    avc_destroy();
844}
845
846void
847SELinuxFlaskInit(void)
848{
849    struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *) 0 };
850    char *ctx;
851    int ret = TRUE;
852
853    switch (selinuxEnforcingState) {
854    case SELINUX_MODE_ENFORCING:
855        LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n");
856        avc_option.value = (char *) 1;
857        break;
858    case SELINUX_MODE_PERMISSIVE:
859        LogMessage(X_INFO, "SELinux: Configured in permissive mode\n");
860        avc_option.value = (char *) 0;
861        break;
862    default:
863        avc_option.type = AVC_OPT_UNUSED;
864        break;
865    }
866
867    /* Set up SELinux stuff */
868    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) SELinuxLog);
869    selinux_set_callback(SELINUX_CB_AUDIT,
870                         (union selinux_callback) SELinuxAudit);
871
872    if (selinux_set_mapping(map) < 0) {
873        if (errno == EINVAL) {
874            ErrorF
875                ("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
897        (subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) ||
898        !dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX,
899                               sizeof(SELinuxObjectRec)) ||
900        !dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX,
901                               sizeof(SELinuxObjectRec)))
902        FatalError("SELinux: Failed to allocate private storage.\n");
903
904    /* Create atoms for doing window labeling */
905    atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
906    if (atom_ctx == BAD_RESOURCE)
907        FatalError("SELinux: Failed to create atom\n");
908    atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
909    if (atom_client_ctx == BAD_RESOURCE)
910        FatalError("SELinux: Failed to create atom\n");
911
912    netlink_fd = avc_netlink_acquire_fd();
913    SetNotifyFd(netlink_fd, SELinuxNetlinkNotify, X_NOTIFY_READ, NULL);
914
915    /* Register callbacks */
916    ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
917    ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
918
919    ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
920    ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
921    ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
922    ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
923    ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
924    ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
925    ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
926    ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
927    ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
928    ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
929    ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
930    ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
931    if (!ret)
932        FatalError("SELinux: Failed to register one or more callbacks\n");
933
934    /* Label objects that were created before we could register ourself */
935    SELinuxLabelInitial();
936}
937