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
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 ********************************************************/
20 #ifdef HAVE_DIX_CONFIG_H
21 #include <dix-config.h>
24 #include "selection.h"
26 #include "windowstr.h"
27 #include "propertyst.h"
28 #include "extnsionst.h"
30 #include "xselinuxint.h"
32 #define CTX_DEV offsetof(SELinuxSubjectRec, dev_create_sid)
33 #define CTX_WIN offsetof(SELinuxSubjectRec, win_create_sid)
34 #define CTX_PRP offsetof(SELinuxSubjectRec, prp_create_sid)
35 #define CTX_SEL offsetof(SELinuxSubjectRec, sel_create_sid)
36 #define USE_PRP offsetof(SELinuxSubjectRec, prp_use_sid)
37 #define USE_SEL offsetof(SELinuxSubjectRec, sel_use_sid)
40 security_context_t octx
;
41 security_context_t dctx
;
51 static security_context_t
52 SELinuxCopyContext(char *ptr
, unsigned len
)
54 security_context_t copy
= malloc(len
+ 1);
58 strncpy(copy
, ptr
, len
);
64 ProcSELinuxQueryVersion(ClientPtr client
)
66 SELinuxQueryVersionReply rep
= {
68 .sequenceNumber
= client
->sequence
,
70 .server_major
= SELINUX_MAJOR_VERSION
,
71 .server_minor
= SELINUX_MINOR_VERSION
73 if (client
->swapped
) {
74 swaps(&rep
.sequenceNumber
);
76 swaps(&rep
.server_major
);
77 swaps(&rep
.server_minor
);
79 WriteToClient(client
, sizeof(rep
), &rep
);
84 SELinuxSendContextReply(ClientPtr client
, security_id_t sid
)
86 SELinuxGetContextReply rep
;
87 security_context_t ctx
= NULL
;
91 if (avc_sid_to_context_raw(sid
, &ctx
) < 0)
93 len
= strlen(ctx
) + 1;
96 rep
= (SELinuxGetContextReply
) {
98 .sequenceNumber
= client
->sequence
,
99 .length
= bytes_to_int32(len
),
103 if (client
->swapped
) {
105 swaps(&rep
.sequenceNumber
);
106 swapl(&rep
.context_len
);
109 WriteToClient(client
, sizeof(SELinuxGetContextReply
), &rep
);
110 WriteToClient(client
, len
, ctx
);
116 ProcSELinuxSetCreateContext(ClientPtr client
, unsigned offset
)
118 PrivateRec
**privPtr
= &client
->devPrivates
;
120 security_context_t ctx
= NULL
;
124 REQUEST(SELinuxSetCreateContextReq
);
125 REQUEST_FIXED_SIZE(SELinuxSetCreateContextReq
, stuff
->context_len
);
127 if (stuff
->context_len
> 0) {
128 ctx
= SELinuxCopyContext((char *) (stuff
+ 1), stuff
->context_len
);
133 ptr
= dixLookupPrivate(privPtr
, subjectKey
);
134 pSid
= (security_id_t
*) (ptr
+ offset
);
138 if (stuff
->context_len
> 0) {
139 if (security_check_context_raw(ctx
) < 0 ||
140 avc_context_to_sid_raw(ctx
, pSid
) < 0)
149 ProcSELinuxGetCreateContext(ClientPtr client
, unsigned offset
)
154 REQUEST_SIZE_MATCH(SELinuxGetCreateContextReq
);
156 if (offset
== CTX_DEV
)
157 ptr
= dixLookupPrivate(&serverClient
->devPrivates
, subjectKey
);
159 ptr
= dixLookupPrivate(&client
->devPrivates
, subjectKey
);
161 pSid
= (security_id_t
*) (ptr
+ offset
);
162 return SELinuxSendContextReply(client
, *pSid
);
166 ProcSELinuxSetDeviceContext(ClientPtr client
)
168 security_context_t ctx
;
171 SELinuxSubjectRec
*subj
;
172 SELinuxObjectRec
*obj
;
175 REQUEST(SELinuxSetContextReq
);
176 REQUEST_FIXED_SIZE(SELinuxSetContextReq
, stuff
->context_len
);
178 if (stuff
->context_len
< 1)
180 ctx
= SELinuxCopyContext((char *) (stuff
+ 1), stuff
->context_len
);
184 rc
= dixLookupDevice(&dev
, stuff
->id
, client
, DixManageAccess
);
188 if (security_check_context_raw(ctx
) < 0 ||
189 avc_context_to_sid_raw(ctx
, &sid
) < 0) {
194 subj
= dixLookupPrivate(&dev
->devPrivates
, subjectKey
);
196 obj
= dixLookupPrivate(&dev
->devPrivates
, objectKey
);
206 ProcSELinuxGetDeviceContext(ClientPtr client
)
209 SELinuxSubjectRec
*subj
;
212 REQUEST(SELinuxGetContextReq
);
213 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
215 rc
= dixLookupDevice(&dev
, stuff
->id
, client
, DixGetAttrAccess
);
219 subj
= dixLookupPrivate(&dev
->devPrivates
, subjectKey
);
220 return SELinuxSendContextReply(client
, subj
->sid
);
224 ProcSELinuxGetDrawableContext(ClientPtr client
)
227 PrivateRec
**privatePtr
;
228 SELinuxObjectRec
*obj
;
231 REQUEST(SELinuxGetContextReq
);
232 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
234 rc
= dixLookupDrawable(&pDraw
, stuff
->id
, client
, 0, DixGetAttrAccess
);
238 if (pDraw
->type
== DRAWABLE_PIXMAP
)
239 privatePtr
= &((PixmapPtr
) pDraw
)->devPrivates
;
241 privatePtr
= &((WindowPtr
) pDraw
)->devPrivates
;
243 obj
= dixLookupPrivate(privatePtr
, objectKey
);
244 return SELinuxSendContextReply(client
, obj
->sid
);
248 ProcSELinuxGetPropertyContext(ClientPtr client
, pointer privKey
)
252 SELinuxObjectRec
*obj
;
255 REQUEST(SELinuxGetPropertyContextReq
);
256 REQUEST_SIZE_MATCH(SELinuxGetPropertyContextReq
);
258 rc
= dixLookupWindow(&pWin
, stuff
->window
, client
, DixGetPropAccess
);
262 rc
= dixLookupProperty(&pProp
, pWin
, stuff
->property
, client
,
267 obj
= dixLookupPrivate(&pProp
->devPrivates
, privKey
);
268 return SELinuxSendContextReply(client
, obj
->sid
);
272 ProcSELinuxGetSelectionContext(ClientPtr client
, pointer privKey
)
275 SELinuxObjectRec
*obj
;
278 REQUEST(SELinuxGetContextReq
);
279 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
281 rc
= dixLookupSelection(&pSel
, stuff
->id
, client
, DixGetAttrAccess
);
285 obj
= dixLookupPrivate(&pSel
->devPrivates
, privKey
);
286 return SELinuxSendContextReply(client
, obj
->sid
);
290 ProcSELinuxGetClientContext(ClientPtr client
)
293 SELinuxSubjectRec
*subj
;
296 REQUEST(SELinuxGetContextReq
);
297 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
299 rc
= dixLookupClient(&target
, stuff
->id
, client
, DixGetAttrAccess
);
303 subj
= dixLookupPrivate(&target
->devPrivates
, subjectKey
);
304 return SELinuxSendContextReply(client
, subj
->sid
);
308 SELinuxPopulateItem(SELinuxListItemRec
* i
, PrivateRec
** privPtr
, CARD32 id
,
311 SELinuxObjectRec
*obj
= dixLookupPrivate(privPtr
, objectKey
);
312 SELinuxObjectRec
*data
= dixLookupPrivate(privPtr
, dataKey
);
314 if (avc_sid_to_context_raw(obj
->sid
, &i
->octx
) < 0)
316 if (avc_sid_to_context_raw(data
->sid
, &i
->dctx
) < 0)
320 i
->octx_len
= bytes_to_int32(strlen(i
->octx
) + 1);
321 i
->dctx_len
= bytes_to_int32(strlen(i
->dctx
) + 1);
323 *size
+= i
->octx_len
+ i
->dctx_len
+ 3;
328 SELinuxFreeItems(SELinuxListItemRec
* items
, int count
)
332 for (k
= 0; k
< count
; k
++) {
333 freecon(items
[k
].octx
);
334 freecon(items
[k
].dctx
);
340 SELinuxSendItemsToClient(ClientPtr client
, SELinuxListItemRec
* items
,
344 SELinuxListItemsReply rep
;
347 buf
= calloc(size
, sizeof(CARD32
));
353 /* Fill in the buffer */
354 for (k
= 0; k
< count
; k
++) {
355 buf
[pos
] = items
[k
].id
;
360 buf
[pos
] = items
[k
].octx_len
* 4;
365 buf
[pos
] = items
[k
].dctx_len
* 4;
370 memcpy((char *) (buf
+ pos
), items
[k
].octx
, strlen(items
[k
].octx
) + 1);
371 pos
+= items
[k
].octx_len
;
372 memcpy((char *) (buf
+ pos
), items
[k
].dctx
, strlen(items
[k
].dctx
) + 1);
373 pos
+= items
[k
].dctx_len
;
376 /* Send reply to client */
377 rep
= (SELinuxListItemsReply
) {
379 .sequenceNumber
= client
->sequence
,
384 if (client
->swapped
) {
386 swaps(&rep
.sequenceNumber
);
390 WriteToClient(client
, sizeof(SELinuxListItemsReply
), &rep
);
391 WriteToClient(client
, size
* 4, buf
);
393 /* Free stuff and return */
397 SELinuxFreeItems(items
, count
);
402 ProcSELinuxListProperties(ClientPtr client
)
406 SELinuxListItemRec
*items
;
407 int rc
, count
, size
, i
;
410 REQUEST(SELinuxGetContextReq
);
411 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
413 rc
= dixLookupWindow(&pWin
, stuff
->id
, client
, DixListPropAccess
);
417 /* Count the number of properties and allocate items */
419 for (pProp
= wUserProps(pWin
); pProp
; pProp
= pProp
->next
)
421 items
= calloc(count
, sizeof(SELinuxListItemRec
));
425 /* Fill in the items and calculate size */
428 for (pProp
= wUserProps(pWin
); pProp
; pProp
= pProp
->next
) {
429 id
= pProp
->propertyName
;
430 rc
= SELinuxPopulateItem(items
+ i
, &pProp
->devPrivates
, id
, &size
);
432 SELinuxFreeItems(items
, count
);
438 return SELinuxSendItemsToClient(client
, items
, size
, count
);
442 ProcSELinuxListSelections(ClientPtr client
)
445 SELinuxListItemRec
*items
;
446 int rc
, count
, size
, i
;
449 REQUEST_SIZE_MATCH(SELinuxGetCreateContextReq
);
451 /* Count the number of selections and allocate items */
453 for (pSel
= CurrentSelections
; pSel
; pSel
= pSel
->next
)
455 items
= calloc(count
, sizeof(SELinuxListItemRec
));
459 /* Fill in the items and calculate size */
462 for (pSel
= CurrentSelections
; pSel
; pSel
= pSel
->next
) {
463 id
= pSel
->selection
;
464 rc
= SELinuxPopulateItem(items
+ i
, &pSel
->devPrivates
, id
, &size
);
466 SELinuxFreeItems(items
, count
);
472 return SELinuxSendItemsToClient(client
, items
, size
, count
);
476 ProcSELinuxDispatch(ClientPtr client
)
479 switch (stuff
->data
) {
480 case X_SELinuxQueryVersion
:
481 return ProcSELinuxQueryVersion(client
);
482 case X_SELinuxSetDeviceCreateContext
:
483 return ProcSELinuxSetCreateContext(client
, CTX_DEV
);
484 case X_SELinuxGetDeviceCreateContext
:
485 return ProcSELinuxGetCreateContext(client
, CTX_DEV
);
486 case X_SELinuxSetDeviceContext
:
487 return ProcSELinuxSetDeviceContext(client
);
488 case X_SELinuxGetDeviceContext
:
489 return ProcSELinuxGetDeviceContext(client
);
490 case X_SELinuxSetDrawableCreateContext
:
491 return ProcSELinuxSetCreateContext(client
, CTX_WIN
);
492 case X_SELinuxGetDrawableCreateContext
:
493 return ProcSELinuxGetCreateContext(client
, CTX_WIN
);
494 case X_SELinuxGetDrawableContext
:
495 return ProcSELinuxGetDrawableContext(client
);
496 case X_SELinuxSetPropertyCreateContext
:
497 return ProcSELinuxSetCreateContext(client
, CTX_PRP
);
498 case X_SELinuxGetPropertyCreateContext
:
499 return ProcSELinuxGetCreateContext(client
, CTX_PRP
);
500 case X_SELinuxSetPropertyUseContext
:
501 return ProcSELinuxSetCreateContext(client
, USE_PRP
);
502 case X_SELinuxGetPropertyUseContext
:
503 return ProcSELinuxGetCreateContext(client
, USE_PRP
);
504 case X_SELinuxGetPropertyContext
:
505 return ProcSELinuxGetPropertyContext(client
, objectKey
);
506 case X_SELinuxGetPropertyDataContext
:
507 return ProcSELinuxGetPropertyContext(client
, dataKey
);
508 case X_SELinuxListProperties
:
509 return ProcSELinuxListProperties(client
);
510 case X_SELinuxSetSelectionCreateContext
:
511 return ProcSELinuxSetCreateContext(client
, CTX_SEL
);
512 case X_SELinuxGetSelectionCreateContext
:
513 return ProcSELinuxGetCreateContext(client
, CTX_SEL
);
514 case X_SELinuxSetSelectionUseContext
:
515 return ProcSELinuxSetCreateContext(client
, USE_SEL
);
516 case X_SELinuxGetSelectionUseContext
:
517 return ProcSELinuxGetCreateContext(client
, USE_SEL
);
518 case X_SELinuxGetSelectionContext
:
519 return ProcSELinuxGetSelectionContext(client
, objectKey
);
520 case X_SELinuxGetSelectionDataContext
:
521 return ProcSELinuxGetSelectionContext(client
, dataKey
);
522 case X_SELinuxListSelections
:
523 return ProcSELinuxListSelections(client
);
524 case X_SELinuxGetClientContext
:
525 return ProcSELinuxGetClientContext(client
);
532 SProcSELinuxQueryVersion(ClientPtr client
)
534 return ProcSELinuxQueryVersion(client
);
538 SProcSELinuxSetCreateContext(ClientPtr client
, unsigned offset
)
540 REQUEST(SELinuxSetCreateContextReq
);
542 REQUEST_AT_LEAST_SIZE(SELinuxSetCreateContextReq
);
543 swapl(&stuff
->context_len
);
544 return ProcSELinuxSetCreateContext(client
, offset
);
548 SProcSELinuxSetDeviceContext(ClientPtr client
)
550 REQUEST(SELinuxSetContextReq
);
552 REQUEST_AT_LEAST_SIZE(SELinuxSetContextReq
);
554 swapl(&stuff
->context_len
);
555 return ProcSELinuxSetDeviceContext(client
);
559 SProcSELinuxGetDeviceContext(ClientPtr client
)
561 REQUEST(SELinuxGetContextReq
);
563 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
565 return ProcSELinuxGetDeviceContext(client
);
569 SProcSELinuxGetDrawableContext(ClientPtr client
)
571 REQUEST(SELinuxGetContextReq
);
573 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
575 return ProcSELinuxGetDrawableContext(client
);
579 SProcSELinuxGetPropertyContext(ClientPtr client
, pointer privKey
)
581 REQUEST(SELinuxGetPropertyContextReq
);
583 REQUEST_SIZE_MATCH(SELinuxGetPropertyContextReq
);
584 swapl(&stuff
->window
);
585 swapl(&stuff
->property
);
586 return ProcSELinuxGetPropertyContext(client
, privKey
);
590 SProcSELinuxGetSelectionContext(ClientPtr client
, pointer privKey
)
592 REQUEST(SELinuxGetContextReq
);
594 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
596 return ProcSELinuxGetSelectionContext(client
, privKey
);
600 SProcSELinuxListProperties(ClientPtr client
)
602 REQUEST(SELinuxGetContextReq
);
604 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
606 return ProcSELinuxListProperties(client
);
610 SProcSELinuxGetClientContext(ClientPtr client
)
612 REQUEST(SELinuxGetContextReq
);
614 REQUEST_SIZE_MATCH(SELinuxGetContextReq
);
616 return ProcSELinuxGetClientContext(client
);
620 SProcSELinuxDispatch(ClientPtr client
)
624 swaps(&stuff
->length
);
626 switch (stuff
->data
) {
627 case X_SELinuxQueryVersion
:
628 return SProcSELinuxQueryVersion(client
);
629 case X_SELinuxSetDeviceCreateContext
:
630 return SProcSELinuxSetCreateContext(client
, CTX_DEV
);
631 case X_SELinuxGetDeviceCreateContext
:
632 return ProcSELinuxGetCreateContext(client
, CTX_DEV
);
633 case X_SELinuxSetDeviceContext
:
634 return SProcSELinuxSetDeviceContext(client
);
635 case X_SELinuxGetDeviceContext
:
636 return SProcSELinuxGetDeviceContext(client
);
637 case X_SELinuxSetDrawableCreateContext
:
638 return SProcSELinuxSetCreateContext(client
, CTX_WIN
);
639 case X_SELinuxGetDrawableCreateContext
:
640 return ProcSELinuxGetCreateContext(client
, CTX_WIN
);
641 case X_SELinuxGetDrawableContext
:
642 return SProcSELinuxGetDrawableContext(client
);
643 case X_SELinuxSetPropertyCreateContext
:
644 return SProcSELinuxSetCreateContext(client
, CTX_PRP
);
645 case X_SELinuxGetPropertyCreateContext
:
646 return ProcSELinuxGetCreateContext(client
, CTX_PRP
);
647 case X_SELinuxSetPropertyUseContext
:
648 return SProcSELinuxSetCreateContext(client
, USE_PRP
);
649 case X_SELinuxGetPropertyUseContext
:
650 return ProcSELinuxGetCreateContext(client
, USE_PRP
);
651 case X_SELinuxGetPropertyContext
:
652 return SProcSELinuxGetPropertyContext(client
, objectKey
);
653 case X_SELinuxGetPropertyDataContext
:
654 return SProcSELinuxGetPropertyContext(client
, dataKey
);
655 case X_SELinuxListProperties
:
656 return SProcSELinuxListProperties(client
);
657 case X_SELinuxSetSelectionCreateContext
:
658 return SProcSELinuxSetCreateContext(client
, CTX_SEL
);
659 case X_SELinuxGetSelectionCreateContext
:
660 return ProcSELinuxGetCreateContext(client
, CTX_SEL
);
661 case X_SELinuxSetSelectionUseContext
:
662 return SProcSELinuxSetCreateContext(client
, USE_SEL
);
663 case X_SELinuxGetSelectionUseContext
:
664 return ProcSELinuxGetCreateContext(client
, USE_SEL
);
665 case X_SELinuxGetSelectionContext
:
666 return SProcSELinuxGetSelectionContext(client
, objectKey
);
667 case X_SELinuxGetSelectionDataContext
:
668 return SProcSELinuxGetSelectionContext(client
, dataKey
);
669 case X_SELinuxListSelections
:
670 return ProcSELinuxListSelections(client
);
671 case X_SELinuxGetClientContext
:
672 return SProcSELinuxGetClientContext(client
);
679 * Extension Setup / Teardown
683 SELinuxResetProc(ExtensionEntry
* extEntry
)
690 SELinuxExtensionInit(void)
692 ExtensionEntry
*extEntry
;
694 /* Check SELinux mode on system, configuration file, and boolean */
695 if (!is_selinux_enabled()) {
696 LogMessage(X_INFO
, "SELinux: Disabled on system\n");
699 if (selinuxEnforcingState
== SELINUX_MODE_DISABLED
) {
700 LogMessage(X_INFO
, "SELinux: Disabled in configuration file\n");
703 if (!security_get_boolean_active("xserver_object_manager")) {
704 LogMessage(X_INFO
, "SELinux: Disabled by boolean\n");
708 /* Set up XACE hooks */
712 /* Add extension to server */
713 extEntry
= AddExtension(SELINUX_EXTENSION_NAME
,
714 SELinuxNumberEvents
, SELinuxNumberErrors
,
715 ProcSELinuxDispatch
, SProcSELinuxDispatch
,
716 SELinuxResetProc
, StandardMinorOpcode
);
718 AddExtensionAlias("Flask", extEntry
);