xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xselinux_hooks.c (29895B)


      1 /************************************************************
      2 
      3 Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
      4 
      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.
     10 
     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.
     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 */
     48 typedef 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 */
     61 DevPrivateKeyRec subjectKeyRec;
     62 DevPrivateKeyRec objectKeyRec;
     63 DevPrivateKeyRec dataKeyRec;
     64 
     65 /* audit file descriptor */
     66 static int audit_fd;
     67 
     68 /* atoms for window label properties */
     69 static Atom atom_ctx;
     70 static Atom atom_client_ctx;
     71 
     72 /* The unlabeled SID */
     73 static security_id_t unlabeled_sid;
     74 
     75 /* forward declarations */
     76 static void SELinuxScreen(CallbackListPtr *, void *, void *);
     77 
     78 /* "true" pointer value for use as callback data */
     79 static void *truep = (void *) 1;
     80 
     81 /*
     82  * Performs an SELinux permission check.
     83  */
     84 static int
     85 SELinuxDoCheck(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  */
    111 static void
    112 SELinuxLabelClient(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  */
    165 static void
    166 SELinuxLabelInitial(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  */
    209 static int
    210 SELinuxLabelResource(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 
    250 static int
    251 SELinuxAudit(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 
    296 static int
    297 SELinuxLog(int type, const char *fmt, ...) _X_ATTRIBUTE_PRINTF(2, 3);
    298 
    299 static int
    300 SELinuxLog(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 
    331 static void
    332 SELinuxDevice(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 
    368 static void
    369 SELinuxSend(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 
    410 static void
    411 SELinuxReceive(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 
    448 static void
    449 SELinuxExtension(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 
    489 static void
    490 SELinuxSelection(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 
    549 static void
    550 SELinuxProperty(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 
    613 static void
    614 SELinuxResource(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 
    672 static void
    673 SELinuxScreen(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 
    704 static void
    705 SELinuxClient(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 
    722 static void
    723 SELinuxServer(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 
    744 static void
    745 SELinuxClientState(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 
    759 static void
    760 SELinuxResourceState(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 
    810 static int netlink_fd;
    811 
    812 static void
    813 SELinuxNetlinkNotify(int fd, int ready, void *data)
    814 {
    815     avc_netlink_check_nb();
    816 }
    817 
    818 void
    819 SELinuxFlaskReset(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 
    846 void
    847 SELinuxFlaskInit(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 }