Imported Upstream version 1.15.1
[deb_xorg-server.git] / Xext / xselinux_hooks.c
CommitLineData
a09e091a
JB
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#include "../os/osdep.h"
45#define _XSELINUX_NEED_FLASK_MAP
46#include "xselinuxint.h"
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 * Performs an SELinux permission check.
84 */
85static int
86SELinuxDoCheck(SELinuxSubjectRec * subj, SELinuxObjectRec * obj,
87 security_class_t class, Mask mode, SELinuxAuditRec * auditdata)
88{
89 /* serverClient requests OK */
90 if (subj->privileged)
91 return Success;
92
93 auditdata->command = subj->command;
94 errno = 0;
95
96 if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref,
97 auditdata) < 0) {
98 if (mode == DixUnknownAccess)
99 return Success; /* DixUnknownAccess requests OK ... for now */
100 if (errno == EACCES)
101 return BadAccess;
102 ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno);
103 return BadValue;
104 }
105
106 return Success;
107}
108
109/*
110 * Labels a newly connected client.
111 */
112static void
113SELinuxLabelClient(ClientPtr client)
114{
115 int fd = XaceGetConnectionNumber(client);
116 SELinuxSubjectRec *subj;
117 SELinuxObjectRec *obj;
118 security_context_t ctx;
119
120 subj = dixLookupPrivate(&client->devPrivates, subjectKey);
121 obj = dixLookupPrivate(&client->devPrivates, objectKey);
122
123 /* Try to get a context from the socket */
124 if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) {
125 /* Otherwise, fall back to a default context */
126 ctx = SELinuxDefaultClientLabel();
127 }
128
129 /* For local clients, try and determine the executable name */
130 if (XaceIsLocal(client)) {
131 /* Get cached command name if CLIENTIDS is enabled. */
132 const char *cmdname = GetClientCmdName(client);
133 Bool cached = (cmdname != NULL);
134
135 /* If CLIENTIDS is disabled, figure out the command name from
136 * scratch. */
137 if (!cmdname) {
138 pid_t pid = DetermineClientPid(client);
139
140 if (pid != -1)
141 DetermineClientCmd(pid, &cmdname, NULL);
142 }
143
144 if (!cmdname)
145 goto finish;
146
147 strncpy(subj->command, cmdname, COMMAND_LEN - 1);
148
149 if (!cached)
150 free((void *) cmdname); /* const char * */
151 }
152
153 finish:
154 /* Get a SID from the context */
155 if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
156 FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n",
157 client->index, ctx);
158
159 obj->sid = subj->sid;
160 freecon(ctx);
161}
162
163/*
164 * Labels initial server objects.
165 */
166static void
167SELinuxLabelInitial(void)
168{
169 int i;
170 XaceScreenAccessRec srec;
171 SELinuxSubjectRec *subj;
172 SELinuxObjectRec *obj;
173 security_context_t ctx;
174 pointer unused;
175
176 /* Do the serverClient */
177 subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
178 obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
179 subj->privileged = 1;
180
181 /* Use the context of the X server process for the serverClient */
182 if (getcon_raw(&ctx) < 0)
183 FatalError("SELinux: couldn't get context of X server process\n");
184
185 /* Get a SID from the context */
186 if (avc_context_to_sid_raw(ctx, &subj->sid) < 0)
187 FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx);
188
189 obj->sid = subj->sid;
190 freecon(ctx);
191
192 srec.client = serverClient;
193 srec.access_mode = DixCreateAccess;
194 srec.status = Success;
195
196 for (i = 0; i < screenInfo.numScreens; i++) {
197 /* Do the screen object */
198 srec.screen = screenInfo.screens[i];
199 SELinuxScreen(NULL, NULL, &srec);
200
201 /* Do the default colormap */
202 dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap,
203 RT_COLORMAP, serverClient, DixCreateAccess);
204 }
205}
206
207/*
208 * Labels new resource objects.
209 */
210static int
211SELinuxLabelResource(XaceResourceAccessRec * rec, SELinuxSubjectRec * subj,
212 SELinuxObjectRec * obj, security_class_t class)
213{
214 int offset;
215 security_id_t tsid;
216
217 /* Check for a create context */
218 if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) {
219 obj->sid = subj->win_create_sid;
220 return Success;
221 }
222
223 if (rec->parent)
224 offset = dixLookupPrivateOffset(rec->ptype);
225
226 if (rec->parent && offset >= 0) {
227 /* Use the SID of the parent object in the labeling operation */
228 PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset);
229 SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey);
230
231 tsid = pobj->sid;
232 }
233 else {
234 /* Use the SID of the subject */
235 tsid = subj->sid;
236 }
237
238 /* Perform a transition to obtain the final SID */
239 if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) {
240 ErrorF("SELinux: a compute_create call failed!\n");
241 return BadValue;
242 }
243
244 return Success;
245}
246
247/*
248 * Libselinux Callbacks
249 */
250
251static int
252SELinuxAudit(void *auditdata,
253 security_class_t class, char *msgbuf, size_t msgbufsize)
254{
255 SELinuxAuditRec *audit = auditdata;
256 ClientPtr client = audit->client;
257 char idNum[16];
258 const char *propertyName, *selectionName;
259 int major = -1, minor = -1;
260
261 if (client) {
262 REQUEST(xReq);
263 if (stuff) {
264 major = client->majorOp;
265 minor = client->minorOp;
266 }
267 }
268 if (audit->id)
269 snprintf(idNum, 16, "%x", audit->id);
270
271 propertyName = audit->property ? NameForAtom(audit->property) : NULL;
272 selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
273
274 return snprintf(msgbuf, msgbufsize,
275 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
276 (major >= 0) ? "request=" : "",
277 (major >= 0) ? LookupRequestName(major, minor) : "",
278 audit->command ? " comm=" : "",
279 audit->command ? audit->command : "",
280 audit->dev ? " xdevice=\"" : "",
281 audit->dev ? audit->dev->name : "",
282 audit->dev ? "\"" : "",
283 audit->id ? " resid=" : "",
284 audit->id ? idNum : "",
285 audit->restype ? " restype=" : "",
286 audit->restype ? LookupResourceName(audit->restype) : "",
287 audit->event ? " event=" : "",
288 audit->event ? LookupEventName(audit->event & 127) : "",
289 audit->property ? " property=" : "",
290 audit->property ? propertyName : "",
291 audit->selection ? " selection=" : "",
292 audit->selection ? selectionName : "",
293 audit->extension ? " extension=" : "",
294 audit->extension ? audit->extension : "");
295}
296
297static int
298SELinuxLog(int type, const char *fmt, ...)
299{
300 va_list ap;
301 char buf[MAX_AUDIT_MESSAGE_LENGTH];
302 int rc, aut;
303
304 switch (type) {
305 case SELINUX_INFO:
306 aut = AUDIT_USER_MAC_POLICY_LOAD;
307 break;
308 case SELINUX_AVC:
309 aut = AUDIT_USER_AVC;
310 break;
311 default:
312 aut = AUDIT_USER_SELINUX_ERR;
313 break;
314 }
315
316 va_start(ap, fmt);
317 vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap);
318 rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0);
319 va_end(ap);
320 LogMessageVerb(X_WARNING, 0, "%s", buf);
321 return 0;
322}
323
324/*
325 * XACE Callbacks
326 */
327
328static void
329SELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata)
330{
331 XaceDeviceAccessRec *rec = calldata;
332 SELinuxSubjectRec *subj;
333 SELinuxObjectRec *obj;
334 SELinuxAuditRec auditdata = {.client = rec->client,.dev = rec->dev };
335 security_class_t cls;
336 int rc;
337
338 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
339 obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey);
340
341 /* If this is a new object that needs labeling, do it now */
342 if (rec->access_mode & DixCreateAccess) {
343 SELinuxSubjectRec *dsubj;
344
345 dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
346
347 if (subj->dev_create_sid) {
348 /* Label the device with the create context */
349 obj->sid = subj->dev_create_sid;
350 dsubj->sid = subj->dev_create_sid;
351 }
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;
403 err:
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;
441 err:
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 }
632 else {
633 /* Yes: use the SID from the resource object itself */
634 class = SELinuxTypeToClass(rec->rtype);
635 privatePtr = DEVPRIV_AT(rec->res, offset);
636 obj = dixLookupPrivate(privatePtr, objectKey);
637 }
638
639 /* If this is a new object that needs labeling, do it now */
640 if (access_mode & DixCreateAccess && offset >= 0) {
641 rc = SELinuxLabelResource(rec, subj, obj, class);
642 if (rc != Success) {
643 rec->status = rc;
644 return;
645 }
646 }
647
648 /* Collapse generic resource permissions down to read/write */
649 if (class == SECCLASS_X_RESOURCE) {
650 access_mode = ! !(rec->access_mode & SELinuxReadMask); /* rd */
651 access_mode |= ! !(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */
652 }
653
654 /* Perform the security check */
655 auditdata.restype = rec->rtype;
656 auditdata.id = rec->id;
657 rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata);
658 if (rc != Success)
659 rec->status = rc;
660
661 /* Perform the background none check on windows */
662 if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) {
663 rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata);
664 if (rc != Success)
665 ((WindowPtr) rec->res)->forcedBG = TRUE;
666 }
667}
668
669static void
670SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata)
671{
672 XaceScreenAccessRec *rec = calldata;
673 SELinuxSubjectRec *subj;
674 SELinuxObjectRec *obj;
675 SELinuxAuditRec auditdata = {.client = rec->client };
676 Mask access_mode = rec->access_mode;
677 int rc;
678
679 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
680 obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey);
681
682 /* If this is a new object that needs labeling, do it now */
683 if (access_mode & DixCreateAccess) {
684 /* Perform a transition to obtain the final SID */
685 if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
686 &obj->sid) < 0) {
687 ErrorF("SELinux: a compute_create call failed!\n");
688 rec->status = BadValue;
689 return;
690 }
691 }
692
693 if (is_saver)
694 access_mode <<= 2;
695
696 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata);
697 if (rc != Success)
698 rec->status = rc;
699}
700
701static void
702SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata)
703{
704 XaceClientAccessRec *rec = calldata;
705 SELinuxSubjectRec *subj;
706 SELinuxObjectRec *obj;
707 SELinuxAuditRec auditdata = {.client = rec->client };
708 int rc;
709
710 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
711 obj = dixLookupPrivate(&rec->target->devPrivates, objectKey);
712
713 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode,
714 &auditdata);
715 if (rc != Success)
716 rec->status = rc;
717}
718
719static void
720SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
721{
722 XaceServerAccessRec *rec = calldata;
723 SELinuxSubjectRec *subj;
724 SELinuxObjectRec *obj;
725 SELinuxAuditRec auditdata = {.client = rec->client };
726 int rc;
727
728 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
729 obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
730
731 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode,
732 &auditdata);
733 if (rc != Success)
734 rec->status = rc;
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
776 if (rc < 0)
777 FatalError("SELinux: Failed to get security context!\n");
778 rc = dixChangeWindowProperty(serverClient,
779 pWin, atom_client_ctx, XA_STRING, 8,
780 PropModeReplace, strlen(ctx), ctx, FALSE);
781 if (rc != Success)
782 FatalError("SELinux: Failed to set label property on window!\n");
783 freecon(ctx);
784 }
785 else
786 FatalError("SELinux: Unexpected unlabeled client found\n");
787
788 obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
789
790 if (obj->sid) {
791 security_context_t ctx;
792 int rc = avc_sid_to_context_raw(obj->sid, &ctx);
793
794 if (rc < 0)
795 FatalError("SELinux: Failed to get security context!\n");
796 rc = dixChangeWindowProperty(serverClient,
797 pWin, atom_ctx, XA_STRING, 8,
798 PropModeReplace, strlen(ctx), ctx, FALSE);
799 if (rc != Success)
800 FatalError("SELinux: Failed to set label property on window!\n");
801 freecon(ctx);
802 }
803 else
804 FatalError("SELinux: Unexpected unlabeled window found\n");
805}
806
807static int netlink_fd;
808
809static void
810SELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask)
811{
812}
813
814static void
815SELinuxWakeupHandler(void *data, int err, void *read_mask)
816{
817 if (FD_ISSET(netlink_fd, (fd_set *) read_mask))
818 avc_netlink_check_nb();
819}
820
821void
822SELinuxFlaskReset(void)
823{
824 /* Unregister callbacks */
825 DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL);
826 DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
827
828 XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
829 XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
830 XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
831 XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
832 XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
833 XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
834 XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
835 XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
836 XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
837 XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
838 XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
839 XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
840
841 /* Tear down SELinux stuff */
842 audit_close(audit_fd);
843 avc_netlink_release_fd();
844 RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
845 NULL);
846 RemoveGeneralSocket(netlink_fd);
847
848 avc_destroy();
849}
850
851void
852SELinuxFlaskInit(void)
853{
854 struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *) 0 };
855 security_context_t ctx;
856 int ret = TRUE;
857
858 switch (selinuxEnforcingState) {
859 case SELINUX_MODE_ENFORCING:
860 LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n");
861 avc_option.value = (char *) 1;
862 break;
863 case SELINUX_MODE_PERMISSIVE:
864 LogMessage(X_INFO, "SELinux: Configured in permissive mode\n");
865 avc_option.value = (char *) 0;
866 break;
867 default:
868 avc_option.type = AVC_OPT_UNUSED;
869 break;
870 }
871
872 /* Set up SELinux stuff */
873 selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) SELinuxLog);
874 selinux_set_callback(SELINUX_CB_AUDIT,
875 (union selinux_callback) SELinuxAudit);
876
877 if (selinux_set_mapping(map) < 0) {
878 if (errno == EINVAL) {
879 ErrorF
880 ("SELinux: Invalid object class mapping, disabling SELinux support.\n");
881 return;
882 }
883 FatalError("SELinux: Failed to set up security class mapping\n");
884 }
885
886 if (avc_open(&avc_option, 1) < 0)
887 FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n");
888
889 if (security_get_initial_context_raw("unlabeled", &ctx) < 0)
890 FatalError("SELinux: Failed to look up unlabeled context\n");
891 if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0)
892 FatalError("SELinux: a context_to_SID call failed!\n");
893 freecon(ctx);
894
895 /* Prepare for auditing */
896 audit_fd = audit_open();
897 if (audit_fd < 0)
898 FatalError("SELinux: Failed to open the system audit log\n");
899
900 /* Allocate private storage */
901 if (!dixRegisterPrivateKey
902 (subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) ||
903 !dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX,
904 sizeof(SELinuxObjectRec)) ||
905 !dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX,
906 sizeof(SELinuxObjectRec)))
907 FatalError("SELinux: Failed to allocate private storage.\n");
908
909 /* Create atoms for doing window labeling */
910 atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
911 if (atom_ctx == BAD_RESOURCE)
912 FatalError("SELinux: Failed to create atom\n");
913 atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
914 if (atom_client_ctx == BAD_RESOURCE)
915 FatalError("SELinux: Failed to create atom\n");
916
917 netlink_fd = avc_netlink_acquire_fd();
918 AddGeneralSocket(netlink_fd);
919 RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler,
920 NULL);
921
922 /* Register callbacks */
923 ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
924 ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
925
926 ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
927 ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
928 ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
929 ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
930 ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
931 ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
932 ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
933 ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
934 ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
935 ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
936 ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
937 ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
938 if (!ret)
939 FatalError("SELinux: Failed to register one or more callbacks\n");
940
941 /* Label objects that were created before we could register ourself */
942 SELinuxLabelInitial();
943}