xwayland: Don't run key behaviors and actions
[xserver.git] / Xext / xselinux_hooks.c
blob4007958a9aff2cd42c9c1aab8267dcc279301725
1 /************************************************************
3 Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 this permission notice appear in supporting documentation. This permission
8 notice shall be included in all copies or substantial portions of the
9 Software.
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 ********************************************************/
21 * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc.
22 * All rights reserved.
25 #include <dix-config.h>
27 #include <errno.h>
28 #include <sys/socket.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <libaudit.h>
32 #include <X11/Xatom.h>
33 #include <X11/Xfuncproto.h>
35 #include "dix/registry_priv.h"
36 #include "os/client_priv.h"
38 #include "selection.h"
39 #include "inputstr.h"
40 #include "scrnintstr.h"
41 #include "windowstr.h"
42 #include "propertyst.h"
43 #include "extnsionst.h"
44 #include "xacestr.h"
45 #define _XSELINUX_NEED_FLASK_MAP
46 #include "xselinuxint.h"
48 /* structure passed to auditing callback */
49 typedef 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;
61 /* private state keys */
62 DevPrivateKeyRec subjectKeyRec;
63 DevPrivateKeyRec objectKeyRec;
64 DevPrivateKeyRec dataKeyRec;
66 /* audit file descriptor */
67 static int audit_fd;
69 /* atoms for window label properties */
70 static Atom atom_ctx;
71 static Atom atom_client_ctx;
73 /* The unlabeled SID */
74 static security_id_t unlabeled_sid;
76 /* forward declarations */
77 static void SELinuxScreen(CallbackListPtr *, void *, void *);
79 /* "true" pointer value for use as callback data */
80 static void *truep = (void *) 1;
83 * Performs an SELinux permission check.
85 static int
86 SELinuxDoCheck(SELinuxSubjectRec * subj, SELinuxObjectRec * obj,
87 security_class_t class, Mask mode, SELinuxAuditRec * auditdata)
89 /* serverClient requests OK */
90 if (subj->privileged)
91 return Success;
93 auditdata->command = subj->command;
94 errno = 0;
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;
106 return Success;
110 * Labels a newly connected client.
112 static void
113 SELinuxLabelClient(ClientPtr client)
115 int fd = XaceGetConnectionNumber(client);
116 SELinuxSubjectRec *subj;
117 SELinuxObjectRec *obj;
118 char *ctx;
120 subj = dixLookupPrivate(&client->devPrivates, subjectKey);
121 obj = dixLookupPrivate(&client->devPrivates, objectKey);
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();
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);
135 /* If CLIENTIDS is disabled, figure out the command name from
136 * scratch. */
137 if (!cmdname) {
138 pid_t pid = DetermineClientPid(client);
140 if (pid != -1)
141 DetermineClientCmd(pid, &cmdname, NULL);
144 if (!cmdname)
145 goto finish;
147 strncpy(subj->command, cmdname, COMMAND_LEN - 1);
149 if (!cached)
150 free((void *) cmdname); /* const char * */
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);
159 obj->sid = subj->sid;
160 freecon(ctx);
164 * Labels initial server objects.
166 static void
167 SELinuxLabelInitial(void)
169 int i;
170 XaceScreenAccessRec srec;
171 SELinuxSubjectRec *subj;
172 SELinuxObjectRec *obj;
173 char *ctx;
174 void *unused;
176 /* Do the serverClient */
177 subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
178 obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
179 subj->privileged = 1;
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");
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);
189 obj->sid = subj->sid;
190 freecon(ctx);
192 srec.client = serverClient;
193 srec.access_mode = DixCreateAccess;
194 srec.status = Success;
196 for (i = 0; i < screenInfo.numScreens; i++) {
197 /* Do the screen object */
198 srec.screen = screenInfo.screens[i];
199 SELinuxScreen(NULL, NULL, &srec);
201 /* Do the default colormap */
202 dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap,
203 X11_RESTYPE_COLORMAP, serverClient, DixCreateAccess);
208 * Labels new resource objects.
210 static int
211 SELinuxLabelResource(XaceResourceAccessRec * rec, SELinuxSubjectRec * subj,
212 SELinuxObjectRec * obj, security_class_t class)
214 int offset;
215 security_id_t tsid;
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;
223 if (rec->parent)
224 offset = dixLookupPrivateOffset(rec->ptype);
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);
231 tsid = pobj->sid;
233 else {
234 /* Use the SID of the subject */
235 tsid = subj->sid;
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;
244 return Success;
248 * Libselinux Callbacks
251 static int
252 SELinuxAudit(void *auditdata,
253 security_class_t class, char *msgbuf, size_t msgbufsize)
255 SELinuxAuditRec *audit = auditdata;
256 ClientPtr client = audit->client;
257 char idNum[16];
258 const char *propertyName, *selectionName;
259 int major = -1, minor = -1;
261 if (client) {
262 REQUEST(xReq);
263 if (stuff) {
264 major = client->majorOp;
265 minor = client->minorOp;
268 if (audit->id)
269 snprintf(idNum, 16, "%x", audit->id);
271 propertyName = audit->property ? NameForAtom(audit->property) : NULL;
272 selectionName = audit->selection ? NameForAtom(audit->selection) : NULL;
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 : "");
297 static int
298 SELinuxLog(int type, const char *fmt, ...) _X_ATTRIBUTE_PRINTF(2, 3);
300 static int
301 SELinuxLog(int type, const char *fmt, ...)
303 va_list ap;
304 char buf[MAX_AUDIT_MESSAGE_LENGTH];
305 int rc, aut;
307 switch (type) {
308 case SELINUX_INFO:
309 aut = AUDIT_USER_MAC_POLICY_LOAD;
310 break;
311 case SELINUX_AVC:
312 aut = AUDIT_USER_AVC;
313 break;
314 default:
315 aut = AUDIT_USER_SELINUX_ERR;
316 break;
319 va_start(ap, fmt);
320 vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap);
321 rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0);
322 (void) rc;
323 va_end(ap);
324 LogMessageVerb(X_WARNING, 0, "%s", buf);
325 return 0;
329 * XACE Callbacks
332 static void
333 SELinuxDevice(CallbackListPtr *pcbl, void *unused, void *calldata)
335 XaceDeviceAccessRec *rec = calldata;
336 SELinuxSubjectRec *subj;
337 SELinuxObjectRec *obj;
338 SELinuxAuditRec auditdata = {.client = rec->client,.dev = rec->dev };
339 security_class_t cls;
340 int rc;
342 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
343 obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey);
345 /* If this is a new object that needs labeling, do it now */
346 if (rec->access_mode & DixCreateAccess) {
347 SELinuxSubjectRec *dsubj;
349 dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
351 if (subj->dev_create_sid) {
352 /* Label the device with the create context */
353 obj->sid = subj->dev_create_sid;
354 dsubj->sid = subj->dev_create_sid;
356 else {
357 /* Label the device directly with the process SID */
358 obj->sid = subj->sid;
359 dsubj->sid = subj->sid;
363 cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD;
364 rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata);
365 if (rc != Success)
366 rec->status = rc;
369 static void
370 SELinuxSend(CallbackListPtr *pcbl, void *unused, void *calldata)
372 XaceSendAccessRec *rec = calldata;
373 SELinuxSubjectRec *subj;
374 SELinuxObjectRec *obj, ev_sid;
375 SELinuxAuditRec auditdata = {.client = rec->client,.dev = rec->dev };
376 security_class_t class;
377 int rc, i, type;
379 if (rec->dev)
380 subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey);
381 else
382 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
384 obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
386 /* Check send permission on window */
387 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess,
388 &auditdata);
389 if (rc != Success)
390 goto err;
392 /* Check send permission on specific event types */
393 for (i = 0; i < rec->count; i++) {
394 type = rec->events[i].u.u.type;
395 class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
397 rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
398 if (rc != Success)
399 goto err;
401 auditdata.event = type;
402 rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata);
403 if (rc != Success)
404 goto err;
406 return;
407 err:
408 rec->status = rc;
411 static void
412 SELinuxReceive(CallbackListPtr *pcbl, void *unused, void *calldata)
414 XaceReceiveAccessRec *rec = calldata;
415 SELinuxSubjectRec *subj;
416 SELinuxObjectRec *obj, ev_sid;
417 SELinuxAuditRec auditdata = {.client = NULL };
418 security_class_t class;
419 int rc, i, type;
421 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
422 obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey);
424 /* Check receive permission on window */
425 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess,
426 &auditdata);
427 if (rc != Success)
428 goto err;
430 /* Check receive permission on specific event types */
431 for (i = 0; i < rec->count; i++) {
432 type = rec->events[i].u.u.type;
433 class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT;
435 rc = SELinuxEventToSID(type, obj->sid, &ev_sid);
436 if (rc != Success)
437 goto err;
439 auditdata.event = type;
440 rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata);
441 if (rc != Success)
442 goto err;
444 return;
445 err:
446 rec->status = rc;
449 static void
450 SELinuxExtension(CallbackListPtr *pcbl, void *unused, void *calldata)
452 XaceExtAccessRec *rec = calldata;
453 SELinuxSubjectRec *subj, *serv;
454 SELinuxObjectRec *obj;
455 SELinuxAuditRec auditdata = {.client = rec->client };
456 int rc;
458 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
459 obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey);
461 /* If this is a new object that needs labeling, do it now */
462 /* XXX there should be a separate callback for this */
463 if (obj->sid == NULL) {
464 security_id_t sid;
466 serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey);
467 rc = SELinuxExtensionToSID(rec->ext->name, &sid);
468 if (rc != Success) {
469 rec->status = rc;
470 return;
473 /* Perform a transition to obtain the final SID */
474 if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
475 &obj->sid) < 0) {
476 ErrorF("SELinux: a SID transition call failed!\n");
477 rec->status = BadValue;
478 return;
482 /* Perform the security check */
483 auditdata.extension = (char *) rec->ext->name;
484 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode,
485 &auditdata);
486 if (rc != Success)
487 rec->status = rc;
490 static void
491 SELinuxSelection(CallbackListPtr *pcbl, void *unused, void *calldata)
493 XaceSelectionAccessRec *rec = calldata;
494 SELinuxSubjectRec *subj;
495 SELinuxObjectRec *obj, *data;
496 Selection *pSel = *rec->ppSel;
497 Atom name = pSel->selection;
498 Mask access_mode = rec->access_mode;
499 SELinuxAuditRec auditdata = {.client = rec->client,.selection = name };
500 security_id_t tsid;
501 int rc;
503 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
504 obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
506 /* If this is a new object that needs labeling, do it now */
507 if (access_mode & DixCreateAccess) {
508 rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly);
509 if (rc != Success)
510 obj->sid = unlabeled_sid;
511 access_mode = DixSetAttrAccess;
513 /* If this is a polyinstantiated object, find the right instance */
514 else if (obj->poly) {
515 rc = SELinuxSelectionToSID(name, subj, &tsid, NULL);
516 if (rc != Success) {
517 rec->status = rc;
518 return;
520 while (pSel->selection != name || obj->sid != tsid) {
521 if ((pSel = pSel->next) == NULL)
522 break;
523 obj = dixLookupPrivate(&pSel->devPrivates, objectKey);
526 if (pSel)
527 *rec->ppSel = pSel;
528 else {
529 rec->status = BadMatch;
530 return;
534 /* Perform the security check */
535 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode,
536 &auditdata);
537 if (rc != Success)
538 rec->status = rc;
540 /* Label the content (advisory only) */
541 if (access_mode & DixSetAttrAccess) {
542 data = dixLookupPrivate(&pSel->devPrivates, dataKey);
543 if (subj->sel_create_sid)
544 data->sid = subj->sel_create_sid;
545 else
546 data->sid = obj->sid;
550 static void
551 SELinuxProperty(CallbackListPtr *pcbl, void *unused, void *calldata)
553 XacePropertyAccessRec *rec = calldata;
554 SELinuxSubjectRec *subj;
555 SELinuxObjectRec *obj, *data;
556 PropertyPtr pProp = *rec->ppProp;
557 Atom name = pProp->propertyName;
558 SELinuxAuditRec auditdata = {.client = rec->client,.property = name };
559 security_id_t tsid;
560 int rc;
562 /* Don't care about the new content check */
563 if (rec->access_mode & DixPostAccess)
564 return;
566 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
567 obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
569 /* If this is a new object that needs labeling, do it now */
570 if (rec->access_mode & DixCreateAccess) {
571 rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly);
572 if (rc != Success) {
573 rec->status = rc;
574 return;
577 /* If this is a polyinstantiated object, find the right instance */
578 else if (obj->poly) {
579 rc = SELinuxPropertyToSID(name, subj, &tsid, NULL);
580 if (rc != Success) {
581 rec->status = rc;
582 return;
584 while (pProp->propertyName != name || obj->sid != tsid) {
585 if ((pProp = pProp->next) == NULL)
586 break;
587 obj = dixLookupPrivate(&pProp->devPrivates, objectKey);
590 if (pProp)
591 *rec->ppProp = pProp;
592 else {
593 rec->status = BadMatch;
594 return;
598 /* Perform the security check */
599 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode,
600 &auditdata);
601 if (rc != Success)
602 rec->status = rc;
604 /* Label the content (advisory only) */
605 if (rec->access_mode & DixWriteAccess) {
606 data = dixLookupPrivate(&pProp->devPrivates, dataKey);
607 if (subj->prp_create_sid)
608 data->sid = subj->prp_create_sid;
609 else
610 data->sid = obj->sid;
614 static void
615 SELinuxResource(CallbackListPtr *pcbl, void *unused, void *calldata)
617 XaceResourceAccessRec *rec = calldata;
618 SELinuxSubjectRec *subj;
619 SELinuxObjectRec *obj;
620 SELinuxAuditRec auditdata = {.client = rec->client };
621 Mask access_mode = rec->access_mode;
622 PrivateRec **privatePtr;
623 security_class_t class;
624 int rc, offset;
626 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
628 /* Determine if the resource object has a devPrivates field */
629 offset = dixLookupPrivateOffset(rec->rtype);
630 if (offset < 0) {
631 /* No: use the SID of the owning client */
632 class = SECCLASS_X_RESOURCE;
633 privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
634 obj = dixLookupPrivate(privatePtr, objectKey);
636 else {
637 /* Yes: use the SID from the resource object itself */
638 class = SELinuxTypeToClass(rec->rtype);
639 privatePtr = DEVPRIV_AT(rec->res, offset);
640 obj = dixLookupPrivate(privatePtr, objectKey);
643 /* If this is a new object that needs labeling, do it now */
644 if (access_mode & DixCreateAccess && offset >= 0) {
645 rc = SELinuxLabelResource(rec, subj, obj, class);
646 if (rc != Success) {
647 rec->status = rc;
648 return;
652 /* Collapse generic resource permissions down to read/write */
653 if (class == SECCLASS_X_RESOURCE) {
654 access_mode = ! !(rec->access_mode & SELinuxReadMask); /* rd */
655 access_mode |= ! !(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */
658 /* Perform the security check */
659 auditdata.restype = rec->rtype;
660 auditdata.id = rec->id;
661 rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata);
662 if (rc != Success)
663 rec->status = rc;
665 /* Perform the background none check on windows */
666 if (access_mode & DixCreateAccess && rec->rtype == X11_RESTYPE_WINDOW) {
667 rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata);
668 if (rc != Success)
669 ((WindowPtr) rec->res)->forcedBG = TRUE;
673 static void
674 SELinuxScreen(CallbackListPtr *pcbl, void *is_saver, void *calldata)
676 XaceScreenAccessRec *rec = calldata;
677 SELinuxSubjectRec *subj;
678 SELinuxObjectRec *obj;
679 SELinuxAuditRec auditdata = {.client = rec->client };
680 Mask access_mode = rec->access_mode;
681 int rc;
683 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
684 obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey);
686 /* If this is a new object that needs labeling, do it now */
687 if (access_mode & DixCreateAccess) {
688 /* Perform a transition to obtain the final SID */
689 if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
690 &obj->sid) < 0) {
691 ErrorF("SELinux: a compute_create call failed!\n");
692 rec->status = BadValue;
693 return;
697 if (is_saver)
698 access_mode <<= 2;
700 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata);
701 if (rc != Success)
702 rec->status = rc;
705 static void
706 SELinuxClient(CallbackListPtr *pcbl, void *unused, void *calldata)
708 XaceClientAccessRec *rec = calldata;
709 SELinuxSubjectRec *subj;
710 SELinuxObjectRec *obj;
711 SELinuxAuditRec auditdata = {.client = rec->client };
712 int rc;
714 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
715 obj = dixLookupPrivate(&rec->target->devPrivates, objectKey);
717 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode,
718 &auditdata);
719 if (rc != Success)
720 rec->status = rc;
723 static void
724 SELinuxServer(CallbackListPtr *pcbl, void *unused, void *calldata)
726 XaceServerAccessRec *rec = calldata;
727 SELinuxSubjectRec *subj;
728 SELinuxObjectRec *obj;
729 SELinuxAuditRec auditdata = {.client = rec->client };
730 int rc;
732 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey);
733 obj = dixLookupPrivate(&serverClient->devPrivates, objectKey);
735 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode,
736 &auditdata);
737 if (rc != Success)
738 rec->status = rc;
742 * DIX Callbacks
745 static void
746 SELinuxClientState(CallbackListPtr *pcbl, void *unused, void *calldata)
748 NewClientInfoRec *pci = calldata;
750 switch (pci->client->clientState) {
751 case ClientStateInitial:
752 SELinuxLabelClient(pci->client);
753 break;
755 default:
756 break;
760 static void
761 SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
763 ResourceStateInfoRec *rec = calldata;
764 SELinuxSubjectRec *subj;
765 SELinuxObjectRec *obj;
766 WindowPtr pWin;
768 if (rec->type != X11_RESTYPE_WINDOW)
769 return;
770 if (rec->state != ResourceStateAdding)
771 return;
773 pWin = (WindowPtr) rec->value;
774 subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
776 if (subj->sid) {
777 char *ctx;
778 int rc = avc_sid_to_context_raw(subj->sid, &ctx);
780 if (rc < 0)
781 FatalError("SELinux: Failed to get security context!\n");
782 rc = dixChangeWindowProperty(serverClient,
783 pWin, atom_client_ctx, XA_STRING, 8,
784 PropModeReplace, strlen(ctx), ctx, FALSE);
785 if (rc != Success)
786 FatalError("SELinux: Failed to set label property on window!\n");
787 freecon(ctx);
789 else
790 FatalError("SELinux: Unexpected unlabeled client found\n");
792 obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
794 if (obj->sid) {
795 char *ctx;
796 int rc = avc_sid_to_context_raw(obj->sid, &ctx);
798 if (rc < 0)
799 FatalError("SELinux: Failed to get security context!\n");
800 rc = dixChangeWindowProperty(serverClient,
801 pWin, atom_ctx, XA_STRING, 8,
802 PropModeReplace, strlen(ctx), ctx, FALSE);
803 if (rc != Success)
804 FatalError("SELinux: Failed to set label property on window!\n");
805 freecon(ctx);
807 else
808 FatalError("SELinux: Unexpected unlabeled window found\n");
811 static int netlink_fd;
813 static void
814 SELinuxNetlinkNotify(int fd, int ready, void *data)
816 avc_netlink_check_nb();
819 void
820 SELinuxFlaskReset(void)
822 /* Unregister callbacks */
823 DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL);
824 DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
826 XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
827 XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
828 XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
829 XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
830 XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
831 XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
832 XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
833 XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
834 XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
835 XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
836 XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
837 XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
839 /* Tear down SELinux stuff */
840 audit_close(audit_fd);
841 avc_netlink_release_fd();
842 RemoveNotifyFd(netlink_fd);
844 avc_destroy();
847 void
848 SELinuxFlaskInit(void)
850 struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *) 0 };
851 char *ctx;
852 int ret = TRUE;
854 switch (selinuxEnforcingState) {
855 case SELINUX_MODE_ENFORCING:
856 LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n");
857 avc_option.value = (char *) 1;
858 break;
859 case SELINUX_MODE_PERMISSIVE:
860 LogMessage(X_INFO, "SELinux: Configured in permissive mode\n");
861 avc_option.value = (char *) 0;
862 break;
863 default:
864 avc_option.type = AVC_OPT_UNUSED;
865 break;
868 /* Set up SELinux stuff */
869 selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) SELinuxLog);
870 selinux_set_callback(SELINUX_CB_AUDIT,
871 (union selinux_callback) SELinuxAudit);
873 if (selinux_set_mapping(map) < 0) {
874 if (errno == EINVAL) {
875 ErrorF
876 ("SELinux: Invalid object class mapping, disabling SELinux support.\n");
877 return;
879 FatalError("SELinux: Failed to set up security class mapping\n");
882 if (avc_open(&avc_option, 1) < 0)
883 FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n");
885 if (security_get_initial_context_raw("unlabeled", &ctx) < 0)
886 FatalError("SELinux: Failed to look up unlabeled context\n");
887 if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0)
888 FatalError("SELinux: a context_to_SID call failed!\n");
889 freecon(ctx);
891 /* Prepare for auditing */
892 audit_fd = audit_open();
893 if (audit_fd < 0)
894 FatalError("SELinux: Failed to open the system audit log\n");
896 /* Allocate private storage */
897 if (!dixRegisterPrivateKey
898 (subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) ||
899 !dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX,
900 sizeof(SELinuxObjectRec)) ||
901 !dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX,
902 sizeof(SELinuxObjectRec)))
903 FatalError("SELinux: Failed to allocate private storage.\n");
905 /* Create atoms for doing window labeling */
906 atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
907 if (atom_ctx == BAD_RESOURCE)
908 FatalError("SELinux: Failed to create atom\n");
909 atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
910 if (atom_client_ctx == BAD_RESOURCE)
911 FatalError("SELinux: Failed to create atom\n");
913 netlink_fd = avc_netlink_acquire_fd();
914 SetNotifyFd(netlink_fd, SELinuxNetlinkNotify, X_NOTIFY_READ, NULL);
916 /* Register callbacks */
917 ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL);
918 ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL);
920 ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL);
921 ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL);
922 ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL);
923 ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL);
924 ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL);
925 ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL);
926 ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL);
927 ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL);
928 ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL);
929 ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL);
930 ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL);
931 ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep);
932 if (!ret)
933 FatalError("SELinux: Failed to register one or more callbacks\n");
935 /* Label objects that were created before we could register ourself */
936 SELinuxLabelInitial();