1/*
2
3Copyright 1996, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include "scrnintstr.h"
32#include "inputstr.h"
33#include "windowstr.h"
34#include "propertyst.h"
35#include "colormapst.h"
36#include "privates.h"
37#include "registry.h"
38#include "xacestr.h"
39#include "securitysrv.h"
40#include <X11/extensions/securproto.h>
41#include "extinit.h"
42#include "protocol-versions.h"
43
44/* Extension stuff */
45static int SecurityErrorBase;   /* first Security error number */
46static int SecurityEventBase;   /* first Security event number */
47
48RESTYPE SecurityAuthorizationResType;   /* resource type for authorizations */
49static RESTYPE RTEventClient;
50
51static CallbackListPtr SecurityValidateGroupCallback = NULL;
52
53/* Private state record */
54static DevPrivateKeyRec stateKeyRec;
55
56#define stateKey (&stateKeyRec)
57
58/* This is what we store as client security state */
59typedef struct {
60    unsigned int haveState  :1;
61    unsigned int live       :1;
62    unsigned int trustLevel :2;
63    XID authId;
64} SecurityStateRec;
65
66/* The only extensions that untrusted clients have access to */
67static const char *SecurityTrustedExtensions[] = {
68    "XC-MISC",
69    "BIG-REQUESTS",
70    NULL
71};
72
73/*
74 * Access modes that untrusted clients are allowed on trusted objects.
75 */
76static const Mask SecurityResourceMask =
77    DixGetAttrAccess | DixReceiveAccess | DixListPropAccess |
78    DixGetPropAccess | DixListAccess;
79static const Mask SecurityWindowExtraMask = DixRemoveAccess;
80static const Mask SecurityRootWindowExtraMask =
81    DixReceiveAccess | DixSendAccess | DixAddAccess | DixRemoveAccess;
82static const Mask SecurityDeviceMask =
83    DixGetAttrAccess | DixReceiveAccess | DixGetFocusAccess |
84    DixGrabAccess | DixSetAttrAccess | DixUseAccess;
85static const Mask SecurityServerMask = DixGetAttrAccess | DixGrabAccess;
86static const Mask SecurityClientMask = DixGetAttrAccess;
87
88/* SecurityAudit
89 *
90 * Arguments:
91 *	format is the formatting string to be used to interpret the
92 *	  remaining arguments.
93 *
94 * Returns: nothing.
95 *
96 * Side Effects:
97 *	Writes the message to the log file if security logging is on.
98 */
99
100static void
101_X_ATTRIBUTE_PRINTF(1, 2)
102SecurityAudit(const char *format, ...)
103{
104    va_list args;
105
106    if (auditTrailLevel < SECURITY_AUDIT_LEVEL)
107        return;
108    va_start(args, format);
109    VAuditF(format, args);
110    va_end(args);
111}                               /* SecurityAudit */
112
113/*
114 * Performs a Security permission check.
115 */
116static int
117SecurityDoCheck(SecurityStateRec * subj, SecurityStateRec * obj,
118                Mask requested, Mask allowed)
119{
120    if (!subj->haveState || !obj->haveState)
121        return Success;
122    if (subj->trustLevel == XSecurityClientTrusted)
123        return Success;
124    if (obj->trustLevel != XSecurityClientTrusted)
125        return Success;
126    if ((requested | allowed) == allowed)
127        return Success;
128
129    return BadAccess;
130}
131
132/*
133 * Labels initial server objects.
134 */
135static void
136SecurityLabelInitial(void)
137{
138    SecurityStateRec *state;
139
140    /* Do the serverClient */
141    state = dixLookupPrivate(&serverClient->devPrivates, stateKey);
142    state->trustLevel = XSecurityClientTrusted;
143    state->haveState = TRUE;
144    state->live = FALSE;
145}
146
147/*
148 * Looks up a request name
149 */
150static _X_INLINE const char *
151SecurityLookupRequestName(ClientPtr client)
152{
153    return LookupRequestName(client->majorOp, client->minorOp);
154}
155
156/* SecurityDeleteAuthorization
157 *
158 * Arguments:
159 *	value is the authorization to delete.
160 *	id is its resource ID.
161 *
162 * Returns: Success.
163 *
164 * Side Effects:
165 *	Frees everything associated with the authorization.
166 */
167
168static int
169SecurityDeleteAuthorization(void *value, XID id)
170{
171    SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr) value;
172    unsigned short name_len, data_len;
173    const char *name;
174    char *data;
175    int status;
176    int i;
177    OtherClientsPtr pEventClient;
178
179    /* Remove the auth using the os layer auth manager */
180
181    status = AuthorizationFromID(pAuth->id, &name_len, &name, &data_len, &data);
182    assert(status);
183    status = RemoveAuthorization(name_len, name, data_len, data);
184    assert(status);
185    (void) status;
186
187    /* free the auth timer if there is one */
188
189    if (pAuth->timer)
190        TimerFree(pAuth->timer);
191
192    /* send revoke events */
193
194    while ((pEventClient = pAuth->eventClients)) {
195        /* send revocation event event */
196        xSecurityAuthorizationRevokedEvent are = {
197            .type = SecurityEventBase + XSecurityAuthorizationRevoked,
198            .authId = pAuth->id
199        };
200        WriteEventsToClient(rClient(pEventClient), 1, (xEvent *) &are);
201        FreeResource(pEventClient->resource, RT_NONE);
202    }
203
204    /* kill all clients using this auth */
205
206    for (i = 1; i < currentMaxClients; i++)
207        if (clients[i]) {
208            SecurityStateRec *state;
209
210            state = dixLookupPrivate(&clients[i]->devPrivates, stateKey);
211            if (state->haveState && state->authId == pAuth->id)
212                CloseDownClient(clients[i]);
213        }
214
215    SecurityAudit("revoked authorization ID %lu\n", (unsigned long)pAuth->id);
216    free(pAuth);
217    return Success;
218
219}                               /* SecurityDeleteAuthorization */
220
221/* resource delete function for RTEventClient */
222static int
223SecurityDeleteAuthorizationEventClient(void *value, XID id)
224{
225    OtherClientsPtr pEventClient, prev = NULL;
226    SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr) value;
227
228    for (pEventClient = pAuth->eventClients;
229         pEventClient; pEventClient = pEventClient->next) {
230        if (pEventClient->resource == id) {
231            if (prev)
232                prev->next = pEventClient->next;
233            else
234                pAuth->eventClients = pEventClient->next;
235            free(pEventClient);
236            return Success;
237        }
238        prev = pEventClient;
239    }
240     /*NOTREACHED*/ return -1;  /* make compiler happy */
241}                               /* SecurityDeleteAuthorizationEventClient */
242
243/* SecurityComputeAuthorizationTimeout
244 *
245 * Arguments:
246 *	pAuth is the authorization for which we are computing the timeout
247 *	seconds is the number of seconds we want to wait
248 *
249 * Returns:
250 *	the number of milliseconds that the auth timer should be set to
251 *
252 * Side Effects:
253 *	Sets pAuth->secondsRemaining to any "overflow" amount of time
254 *	that didn't fit in 32 bits worth of milliseconds
255 */
256
257static CARD32
258SecurityComputeAuthorizationTimeout(SecurityAuthorizationPtr pAuth,
259                                    unsigned int seconds)
260{
261    /* maxSecs is the number of full seconds that can be expressed in
262     * 32 bits worth of milliseconds
263     */
264    CARD32 maxSecs = (CARD32) (~0) / (CARD32) MILLI_PER_SECOND;
265
266    if (seconds > maxSecs) {    /* only come here if we want to wait more than 49 days */
267        pAuth->secondsRemaining = seconds - maxSecs;
268        return maxSecs * MILLI_PER_SECOND;
269    }
270    else {                      /* by far the common case */
271        pAuth->secondsRemaining = 0;
272        return seconds * MILLI_PER_SECOND;
273    }
274}                               /* SecurityStartAuthorizationTimer */
275
276/* SecurityAuthorizationExpired
277 *
278 * This function is passed as an argument to TimerSet and gets called from
279 * the timer manager in the os layer when its time is up.
280 *
281 * Arguments:
282 *	timer is the timer for this authorization.
283 *	time is the current time.
284 *	pval is the authorization whose time is up.
285 *
286 * Returns:
287 *	A new time delay in milliseconds if the timer should wait some
288 *	more, else zero.
289 *
290 * Side Effects:
291 *	Frees the authorization resource if the timeout period is really
292 *	over, otherwise recomputes pAuth->secondsRemaining.
293 */
294
295static CARD32
296SecurityAuthorizationExpired(OsTimerPtr timer, CARD32 time, void *pval)
297{
298    SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr) pval;
299
300    assert(pAuth->timer == timer);
301
302    if (pAuth->secondsRemaining) {
303        return SecurityComputeAuthorizationTimeout(pAuth,
304                                                   pAuth->secondsRemaining);
305    }
306    else {
307        FreeResource(pAuth->id, RT_NONE);
308        return 0;
309    }
310}                               /* SecurityAuthorizationExpired */
311
312/* SecurityStartAuthorizationTimer
313 *
314 * Arguments:
315 *	pAuth is the authorization whose timer should be started.
316 *
317 * Returns: nothing.
318 *
319 * Side Effects:
320 *	A timer is started, set to expire after the timeout period for
321 *	this authorization.  When it expires, the function
322 *	SecurityAuthorizationExpired will be called.
323 */
324
325static void
326SecurityStartAuthorizationTimer(SecurityAuthorizationPtr pAuth)
327{
328    pAuth->timer = TimerSet(pAuth->timer, 0,
329                            SecurityComputeAuthorizationTimeout(pAuth,
330                                                                pAuth->timeout),
331                            SecurityAuthorizationExpired, pAuth);
332}                               /* SecurityStartAuthorizationTimer */
333
334/* Proc functions all take a client argument, execute the request in
335 * client->requestBuffer, and return a protocol error status.
336 */
337
338static int
339ProcSecurityQueryVersion(ClientPtr client)
340{
341    /* REQUEST(xSecurityQueryVersionReq); */
342    xSecurityQueryVersionReply rep = {
343        .type = X_Reply,
344        .sequenceNumber = client->sequence,
345        .length = 0,
346        .majorVersion = SERVER_SECURITY_MAJOR_VERSION,
347        .minorVersion = SERVER_SECURITY_MINOR_VERSION
348    };
349
350    REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
351
352    if (client->swapped) {
353        swaps(&rep.sequenceNumber);
354        swaps(&rep.majorVersion);
355        swaps(&rep.minorVersion);
356    }
357    WriteToClient(client, SIZEOF(xSecurityQueryVersionReply), &rep);
358    return Success;
359}                               /* ProcSecurityQueryVersion */
360
361static int
362SecurityEventSelectForAuthorization(SecurityAuthorizationPtr pAuth,
363                                    ClientPtr client, Mask mask)
364{
365    OtherClients *pEventClient;
366
367    for (pEventClient = pAuth->eventClients;
368         pEventClient; pEventClient = pEventClient->next) {
369        if (SameClient(pEventClient, client)) {
370            if (mask == 0)
371                FreeResource(pEventClient->resource, RT_NONE);
372            else
373                pEventClient->mask = mask;
374            return Success;
375        }
376    }
377
378    pEventClient = malloc(sizeof(OtherClients));
379    if (!pEventClient)
380        return BadAlloc;
381    pEventClient->mask = mask;
382    pEventClient->resource = FakeClientID(client->index);
383    pEventClient->next = pAuth->eventClients;
384    if (!AddResource(pEventClient->resource, RTEventClient, (void *) pAuth)) {
385        free(pEventClient);
386        return BadAlloc;
387    }
388    pAuth->eventClients = pEventClient;
389
390    return Success;
391}                               /* SecurityEventSelectForAuthorization */
392
393static int
394ProcSecurityGenerateAuthorization(ClientPtr client)
395{
396    REQUEST(xSecurityGenerateAuthorizationReq);
397    int len;                    /* request length in CARD32s */
398    Bool removeAuth = FALSE;    /* if bailout, call RemoveAuthorization? */
399    SecurityAuthorizationPtr pAuth = NULL;      /* auth we are creating */
400    int err;                    /* error to return from this function */
401    XID authId;                 /* authorization ID assigned by os layer */
402    xSecurityGenerateAuthorizationReply rep;    /* reply struct */
403    unsigned int trustLevel;    /* trust level of new auth */
404    XID group;                  /* group of new auth */
405    CARD32 timeout;             /* timeout of new auth */
406    CARD32 *values;             /* list of supplied attributes */
407    char *protoname;            /* auth proto name sent in request */
408    char *protodata;            /* auth proto data sent in request */
409    unsigned int authdata_len;  /* # bytes of generated auth data */
410    char *pAuthdata;            /* generated auth data */
411    Mask eventMask;             /* what events on this auth does client want */
412
413    /* check request length */
414
415    REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
416    len = bytes_to_int32(SIZEOF(xSecurityGenerateAuthorizationReq));
417    len += bytes_to_int32(stuff->nbytesAuthProto);
418    len += bytes_to_int32(stuff->nbytesAuthData);
419    values = ((CARD32 *) stuff) + len;
420    len += Ones(stuff->valueMask);
421    if (client->req_len != len)
422        return BadLength;
423
424    /* check valuemask */
425    if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes) {
426        client->errorValue = stuff->valueMask;
427        return BadValue;
428    }
429
430    /* check timeout */
431    timeout = 60;
432    if (stuff->valueMask & XSecurityTimeout) {
433        timeout = *values++;
434    }
435
436    /* check trustLevel */
437    trustLevel = XSecurityClientUntrusted;
438    if (stuff->valueMask & XSecurityTrustLevel) {
439        trustLevel = *values++;
440        if (trustLevel != XSecurityClientTrusted &&
441            trustLevel != XSecurityClientUntrusted) {
442            client->errorValue = trustLevel;
443            return BadValue;
444        }
445    }
446
447    /* check group */
448    group = None;
449    if (stuff->valueMask & XSecurityGroup) {
450        group = *values++;
451        if (SecurityValidateGroupCallback) {
452            SecurityValidateGroupInfoRec vgi;
453
454            vgi.group = group;
455            vgi.valid = FALSE;
456            CallCallbacks(&SecurityValidateGroupCallback, (void *) &vgi);
457
458            /* if nobody said they recognized it, it's an error */
459
460            if (!vgi.valid) {
461                client->errorValue = group;
462                return BadValue;
463            }
464        }
465    }
466
467    /* check event mask */
468    eventMask = 0;
469    if (stuff->valueMask & XSecurityEventMask) {
470        eventMask = *values++;
471        if (eventMask & ~XSecurityAllEventMasks) {
472            client->errorValue = eventMask;
473            return BadValue;
474        }
475    }
476
477    protoname = (char *) &stuff[1];
478    protodata = protoname + bytes_to_int32(stuff->nbytesAuthProto);
479
480    /* call os layer to generate the authorization */
481
482    authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname,
483                                   stuff->nbytesAuthData, protodata,
484                                   &authdata_len, &pAuthdata);
485    if ((XID) ~0L == authId) {
486        err = SecurityErrorBase + XSecurityBadAuthorizationProtocol;
487        goto bailout;
488    }
489
490    /* now that we've added the auth, remember to remove it if we have to
491     * abort the request for some reason (like allocation failure)
492     */
493    removeAuth = TRUE;
494
495    /* associate additional information with this auth ID */
496
497    pAuth = malloc(sizeof(SecurityAuthorizationRec));
498    if (!pAuth) {
499        err = BadAlloc;
500        goto bailout;
501    }
502
503    /* fill in the auth fields */
504
505    pAuth->id = authId;
506    pAuth->timeout = timeout;
507    pAuth->group = group;
508    pAuth->trustLevel = trustLevel;
509    pAuth->refcnt = 0;          /* the auth was just created; nobody's using it yet */
510    pAuth->secondsRemaining = 0;
511    pAuth->timer = NULL;
512    pAuth->eventClients = NULL;
513
514    /* handle event selection */
515    if (eventMask) {
516        err = SecurityEventSelectForAuthorization(pAuth, client, eventMask);
517        if (err != Success)
518            goto bailout;
519    }
520
521    if (!AddResource(authId, SecurityAuthorizationResType, pAuth)) {
522        err = BadAlloc;
523        goto bailout;
524    }
525
526    /* start the timer ticking */
527
528    if (pAuth->timeout != 0)
529        SecurityStartAuthorizationTimer(pAuth);
530
531    /* tell client the auth id and data */
532
533    rep = (xSecurityGenerateAuthorizationReply) {
534        .type = X_Reply,
535        .sequenceNumber = client->sequence,
536        .length = bytes_to_int32(authdata_len),
537        .authId = authId,
538        .dataLength = authdata_len
539    };
540
541    if (client->swapped) {
542        swapl(&rep.length);
543        swaps(&rep.sequenceNumber);
544        swapl(&rep.authId);
545        swaps(&rep.dataLength);
546    }
547
548    WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply), &rep);
549    WriteToClient(client, authdata_len, pAuthdata);
550
551    SecurityAudit
552        ("client %d generated authorization %lu trust %d timeout %lu group %lu events %lu\n",
553         client->index, (unsigned long)pAuth->id, pAuth->trustLevel, (unsigned long)pAuth->timeout,
554         (unsigned long)pAuth->group, (unsigned long)eventMask);
555
556    /* the request succeeded; don't call RemoveAuthorization or free pAuth */
557    return Success;
558
559 bailout:
560    if (removeAuth)
561        RemoveAuthorization(stuff->nbytesAuthProto, protoname,
562                            authdata_len, pAuthdata);
563    free(pAuth);
564    return err;
565
566}                               /* ProcSecurityGenerateAuthorization */
567
568static int
569ProcSecurityRevokeAuthorization(ClientPtr client)
570{
571    REQUEST(xSecurityRevokeAuthorizationReq);
572    SecurityAuthorizationPtr pAuth;
573    int rc;
574
575    REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
576
577    rc = dixLookupResourceByType((void **) &pAuth, stuff->authId,
578                                 SecurityAuthorizationResType, client,
579                                 DixDestroyAccess);
580    if (rc != Success)
581        return rc;
582
583    FreeResource(stuff->authId, RT_NONE);
584    return Success;
585}                               /* ProcSecurityRevokeAuthorization */
586
587static int
588ProcSecurityDispatch(ClientPtr client)
589{
590    REQUEST(xReq);
591
592    switch (stuff->data) {
593    case X_SecurityQueryVersion:
594        return ProcSecurityQueryVersion(client);
595    case X_SecurityGenerateAuthorization:
596        return ProcSecurityGenerateAuthorization(client);
597    case X_SecurityRevokeAuthorization:
598        return ProcSecurityRevokeAuthorization(client);
599    default:
600        return BadRequest;
601    }
602}                               /* ProcSecurityDispatch */
603
604static int _X_COLD
605SProcSecurityQueryVersion(ClientPtr client)
606{
607    REQUEST(xSecurityQueryVersionReq);
608
609    swaps(&stuff->length);
610    REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
611    swaps(&stuff->majorVersion);
612    swaps(&stuff->minorVersion);
613    return ProcSecurityQueryVersion(client);
614}                               /* SProcSecurityQueryVersion */
615
616static int _X_COLD
617SProcSecurityGenerateAuthorization(ClientPtr client)
618{
619    REQUEST(xSecurityGenerateAuthorizationReq);
620    CARD32 *values;
621    unsigned long nvalues;
622    int values_offset;
623
624    swaps(&stuff->length);
625    REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
626    swaps(&stuff->nbytesAuthProto);
627    swaps(&stuff->nbytesAuthData);
628    swapl(&stuff->valueMask);
629    values_offset = bytes_to_int32(stuff->nbytesAuthProto) +
630        bytes_to_int32(stuff->nbytesAuthData);
631    if (values_offset >
632        stuff->length - bytes_to_int32(sz_xSecurityGenerateAuthorizationReq))
633        return BadLength;
634    values = (CARD32 *) (&stuff[1]) + values_offset;
635    nvalues = (((CARD32 *) stuff) + stuff->length) - values;
636    SwapLongs(values, nvalues);
637    return ProcSecurityGenerateAuthorization(client);
638}                               /* SProcSecurityGenerateAuthorization */
639
640static int _X_COLD
641SProcSecurityRevokeAuthorization(ClientPtr client)
642{
643    REQUEST(xSecurityRevokeAuthorizationReq);
644
645    swaps(&stuff->length);
646    REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
647    swapl(&stuff->authId);
648    return ProcSecurityRevokeAuthorization(client);
649}                               /* SProcSecurityRevokeAuthorization */
650
651static int _X_COLD
652SProcSecurityDispatch(ClientPtr client)
653{
654    REQUEST(xReq);
655
656    switch (stuff->data) {
657    case X_SecurityQueryVersion:
658        return SProcSecurityQueryVersion(client);
659    case X_SecurityGenerateAuthorization:
660        return SProcSecurityGenerateAuthorization(client);
661    case X_SecurityRevokeAuthorization:
662        return SProcSecurityRevokeAuthorization(client);
663    default:
664        return BadRequest;
665    }
666}                               /* SProcSecurityDispatch */
667
668static void _X_COLD
669SwapSecurityAuthorizationRevokedEvent(xSecurityAuthorizationRevokedEvent * from,
670                                      xSecurityAuthorizationRevokedEvent * to)
671{
672    to->type = from->type;
673    to->detail = from->detail;
674    cpswaps(from->sequenceNumber, to->sequenceNumber);
675    cpswapl(from->authId, to->authId);
676}
677
678/* SecurityCheckDeviceAccess
679 *
680 * Arguments:
681 *	client is the client attempting to access a device.
682 *	dev is the device being accessed.
683 *	fromRequest is TRUE if the device access is a direct result of
684 *	  the client executing some request and FALSE if it is a
685 *	  result of the server trying to send an event (e.g. KeymapNotify)
686 *	  to the client.
687 * Returns:
688 *	TRUE if the device access should be allowed, else FALSE.
689 *
690 * Side Effects:
691 *	An audit message is generated if access is denied.
692 */
693
694static void
695SecurityDevice(CallbackListPtr *pcbl, void *unused, void *calldata)
696{
697    XaceDeviceAccessRec *rec = calldata;
698    SecurityStateRec *subj, *obj;
699    Mask requested = rec->access_mode;
700    Mask allowed = SecurityDeviceMask;
701
702    subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
703    obj = dixLookupPrivate(&serverClient->devPrivates, stateKey);
704
705    if (rec->dev != inputInfo.keyboard)
706        /* this extension only supports the core keyboard */
707        allowed = requested;
708
709    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
710        SecurityAudit("Security denied client %d keyboard access on request "
711                      "%s\n", rec->client->index,
712                      SecurityLookupRequestName(rec->client));
713        rec->status = BadAccess;
714    }
715}
716
717/* SecurityResource
718 *
719 * This function gets plugged into client->CheckAccess and is called from
720 * SecurityLookupIDByType/Class to determine if the client can access the
721 * resource.
722 *
723 * Arguments:
724 *	client is the client doing the resource access.
725 *	id is the resource id.
726 *	rtype is its type or class.
727 *	access_mode represents the intended use of the resource; see
728 *	  resource.h.
729 *	res is a pointer to the resource structure for this resource.
730 *
731 * Returns:
732 *	If access is granted, the value of rval that was passed in, else FALSE.
733 *
734 * Side Effects:
735 *	Disallowed resource accesses are audited.
736 */
737
738static void
739SecurityResource(CallbackListPtr *pcbl, void *unused, void *calldata)
740{
741    XaceResourceAccessRec *rec = calldata;
742    SecurityStateRec *subj, *obj;
743    int cid = CLIENT_ID(rec->id);
744    Mask requested = rec->access_mode;
745    Mask allowed = SecurityResourceMask;
746
747    subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
748
749    /* disable background None for untrusted windows */
750    if ((requested & DixCreateAccess) && (rec->rtype == RT_WINDOW))
751        if (subj->haveState && subj->trustLevel != XSecurityClientTrusted)
752            ((WindowPtr) rec->res)->forcedBG = TRUE;
753
754    /* additional permissions for specific resource types */
755    if (rec->rtype == RT_WINDOW)
756        allowed |= SecurityWindowExtraMask;
757
758    /* special checks for server-owned resources */
759    if (cid == 0) {
760        if (rec->rtype & RC_DRAWABLE)
761            /* additional operations allowed on root windows */
762            allowed |= SecurityRootWindowExtraMask;
763
764        else if (rec->rtype == RT_COLORMAP)
765            /* allow access to default colormaps */
766            allowed = requested;
767
768        else
769            /* allow read access to other server-owned resources */
770            allowed |= DixReadAccess;
771    }
772
773    if (clients[cid] != NULL) {
774        obj = dixLookupPrivate(&clients[cid]->devPrivates, stateKey);
775        if (SecurityDoCheck(subj, obj, requested, allowed) == Success)
776            return;
777    }
778
779    SecurityAudit("Security: denied client %d access %lx to resource 0x%lx "
780                  "of client %d on request %s\n", rec->client->index,
781                  (unsigned long)requested, (unsigned long)rec->id, cid,
782                  SecurityLookupRequestName(rec->client));
783    rec->status = BadAccess;    /* deny access */
784}
785
786static void
787SecurityExtension(CallbackListPtr *pcbl, void *unused, void *calldata)
788{
789    XaceExtAccessRec *rec = calldata;
790    SecurityStateRec *subj;
791    int i = 0;
792
793    subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
794
795    if (subj->haveState && subj->trustLevel == XSecurityClientTrusted)
796        return;
797
798    while (SecurityTrustedExtensions[i])
799        if (!strcmp(SecurityTrustedExtensions[i++], rec->ext->name))
800            return;
801
802    SecurityAudit("Security: denied client %d access to extension "
803                  "%s on request %s\n",
804                  rec->client->index, rec->ext->name,
805                  SecurityLookupRequestName(rec->client));
806    rec->status = BadAccess;
807}
808
809static void
810SecurityServer(CallbackListPtr *pcbl, void *unused, void *calldata)
811{
812    XaceServerAccessRec *rec = calldata;
813    SecurityStateRec *subj, *obj;
814    Mask requested = rec->access_mode;
815    Mask allowed = SecurityServerMask;
816
817    subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
818    obj = dixLookupPrivate(&serverClient->devPrivates, stateKey);
819
820    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
821        SecurityAudit("Security: denied client %d access to server "
822                      "configuration request %s\n", rec->client->index,
823                      SecurityLookupRequestName(rec->client));
824        rec->status = BadAccess;
825    }
826}
827
828static void
829SecurityClient(CallbackListPtr *pcbl, void *unused, void *calldata)
830{
831    XaceClientAccessRec *rec = calldata;
832    SecurityStateRec *subj, *obj;
833    Mask requested = rec->access_mode;
834    Mask allowed = SecurityClientMask;
835
836    subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
837    obj = dixLookupPrivate(&rec->target->devPrivates, stateKey);
838
839    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
840        SecurityAudit("Security: denied client %d access to client %d on "
841                      "request %s\n", rec->client->index, rec->target->index,
842                      SecurityLookupRequestName(rec->client));
843        rec->status = BadAccess;
844    }
845}
846
847static void
848SecurityProperty(CallbackListPtr *pcbl, void *unused, void *calldata)
849{
850    XacePropertyAccessRec *rec = calldata;
851    SecurityStateRec *subj, *obj;
852    ATOM name = (*rec->ppProp)->propertyName;
853    Mask requested = rec->access_mode;
854    Mask allowed = SecurityResourceMask | DixReadAccess;
855
856    subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
857    obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
858
859    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
860        SecurityAudit("Security: denied client %d access to property %s "
861                      "(atom 0x%x) window 0x%lx of client %d on request %s\n",
862                      rec->client->index, NameForAtom(name), name,
863                      (unsigned long)rec->pWin->drawable.id, wClient(rec->pWin)->index,
864                      SecurityLookupRequestName(rec->client));
865        rec->status = BadAccess;
866    }
867}
868
869static void
870SecuritySend(CallbackListPtr *pcbl, void *unused, void *calldata)
871{
872    XaceSendAccessRec *rec = calldata;
873    SecurityStateRec *subj, *obj;
874
875    if (rec->client) {
876        int i;
877
878        subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
879        obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
880
881        if (SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success)
882            return;
883
884        for (i = 0; i < rec->count; i++)
885            if (rec->events[i].u.u.type != UnmapNotify &&
886                rec->events[i].u.u.type != ConfigureRequest &&
887                rec->events[i].u.u.type != ClientMessage) {
888
889                SecurityAudit("Security: denied client %d from sending event "
890                              "of type %s to window 0x%lx of client %d\n",
891                              rec->client->index,
892                              LookupEventName(rec->events[i].u.u.type),
893                              (unsigned long)rec->pWin->drawable.id,
894                              wClient(rec->pWin)->index);
895                rec->status = BadAccess;
896                return;
897            }
898    }
899}
900
901static void
902SecurityReceive(CallbackListPtr *pcbl, void *unused, void *calldata)
903{
904    XaceReceiveAccessRec *rec = calldata;
905    SecurityStateRec *subj, *obj;
906
907    subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
908    obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
909
910    if (SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success)
911        return;
912
913    SecurityAudit("Security: denied client %d from receiving an event "
914                  "sent to window 0x%lx of client %d\n",
915                  rec->client->index, (unsigned long)rec->pWin->drawable.id,
916                  wClient(rec->pWin)->index);
917    rec->status = BadAccess;
918}
919
920/* SecurityClientStateCallback
921 *
922 * Arguments:
923 *	pcbl is &ClientStateCallback.
924 *	nullata is NULL.
925 *	calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
926 *	which contains information about client state changes.
927 *
928 * Returns: nothing.
929 *
930 * Side Effects:
931 *
932 * If a new client is connecting, its authorization ID is copied to
933 * client->authID.  If this is a generated authorization, its reference
934 * count is bumped, its timer is cancelled if it was running, and its
935 * trustlevel is copied to TRUSTLEVEL(client).
936 *
937 * If a client is disconnecting and the client was using a generated
938 * authorization, the authorization's reference count is decremented, and
939 * if it is now zero, the timer for this authorization is started.
940 */
941
942static void
943SecurityClientState(CallbackListPtr *pcbl, void *unused, void *calldata)
944{
945    NewClientInfoRec *pci = calldata;
946    SecurityStateRec *state;
947    SecurityAuthorizationPtr pAuth;
948    int rc;
949
950    state = dixLookupPrivate(&pci->client->devPrivates, stateKey);
951
952    switch (pci->client->clientState) {
953    case ClientStateInitial:
954        state->trustLevel = XSecurityClientTrusted;
955        state->authId = None;
956        state->haveState = TRUE;
957        state->live = FALSE;
958        break;
959
960    case ClientStateRunning:
961        state->authId = AuthorizationIDOfClient(pci->client);
962        rc = dixLookupResourceByType((void **) &pAuth, state->authId,
963                                     SecurityAuthorizationResType, serverClient,
964                                     DixGetAttrAccess);
965        if (rc == Success) {
966            /* it is a generated authorization */
967            pAuth->refcnt++;
968            state->live = TRUE;
969            if (pAuth->refcnt == 1 && pAuth->timer)
970                TimerCancel(pAuth->timer);
971
972            state->trustLevel = pAuth->trustLevel;
973        }
974        break;
975
976    case ClientStateGone:
977    case ClientStateRetained:
978        rc = dixLookupResourceByType((void **) &pAuth, state->authId,
979                                     SecurityAuthorizationResType, serverClient,
980                                     DixGetAttrAccess);
981        if (rc == Success && state->live) {
982            /* it is a generated authorization */
983            pAuth->refcnt--;
984            state->live = FALSE;
985            if (pAuth->refcnt == 0)
986                SecurityStartAuthorizationTimer(pAuth);
987        }
988        break;
989
990    default:
991        break;
992    }
993}
994
995/* SecurityResetProc
996 *
997 * Arguments:
998 *	extEntry is the extension information for the security extension.
999 *
1000 * Returns: nothing.
1001 *
1002 * Side Effects:
1003 *	Performs any cleanup needed by Security at server shutdown time.
1004 */
1005
1006static void
1007SecurityResetProc(ExtensionEntry * extEntry)
1008{
1009    /* Unregister callbacks */
1010    DeleteCallback(&ClientStateCallback, SecurityClientState, NULL);
1011
1012    XaceDeleteCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL);
1013    XaceDeleteCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL);
1014    XaceDeleteCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL);
1015    XaceDeleteCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL);
1016    XaceDeleteCallback(XACE_SEND_ACCESS, SecuritySend, NULL);
1017    XaceDeleteCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL);
1018    XaceDeleteCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL);
1019    XaceDeleteCallback(XACE_EXT_ACCESS, SecurityExtension, NULL);
1020    XaceDeleteCallback(XACE_SERVER_ACCESS, SecurityServer, NULL);
1021}
1022
1023/* SecurityExtensionInit
1024 *
1025 * Arguments: none.
1026 *
1027 * Returns: nothing.
1028 *
1029 * Side Effects:
1030 *	Enables the Security extension if possible.
1031 */
1032
1033void
1034SecurityExtensionInit(void)
1035{
1036    ExtensionEntry *extEntry;
1037    int ret = TRUE;
1038
1039    SecurityAuthorizationResType =
1040        CreateNewResourceType(SecurityDeleteAuthorization,
1041                              "SecurityAuthorization");
1042
1043    RTEventClient =
1044        CreateNewResourceType(SecurityDeleteAuthorizationEventClient,
1045                              "SecurityEventClient");
1046
1047    if (!SecurityAuthorizationResType || !RTEventClient)
1048        return;
1049
1050    RTEventClient |= RC_NEVERRETAIN;
1051
1052    /* Allocate the private storage */
1053    if (!dixRegisterPrivateKey
1054        (stateKey, PRIVATE_CLIENT, sizeof(SecurityStateRec)))
1055        FatalError("SecurityExtensionSetup: Can't allocate client private.\n");
1056
1057    /* Register callbacks */
1058    ret &= AddCallback(&ClientStateCallback, SecurityClientState, NULL);
1059
1060    ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL);
1061    ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL);
1062    ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL);
1063    ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL);
1064    ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SecuritySend, NULL);
1065    ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL);
1066    ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL);
1067    ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SecurityExtension, NULL);
1068    ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SecurityServer, NULL);
1069
1070    if (!ret)
1071        FatalError("SecurityExtensionSetup: Failed to register callbacks\n");
1072
1073    /* Add extension to server */
1074    extEntry = AddExtension(SECURITY_EXTENSION_NAME,
1075                            XSecurityNumberEvents, XSecurityNumberErrors,
1076                            ProcSecurityDispatch, SProcSecurityDispatch,
1077                            SecurityResetProc, StandardMinorOpcode);
1078
1079    SecurityErrorBase = extEntry->errorBase;
1080    SecurityEventBase = extEntry->eventBase;
1081
1082    EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] =
1083        (EventSwapPtr) SwapSecurityAuthorizationRevokedEvent;
1084
1085    SetResourceTypeErrorValue(SecurityAuthorizationResType,
1086                              SecurityErrorBase + XSecurityBadAuthorization);
1087
1088    /* Label objects that were created before we could register ourself */
1089    SecurityLabelInitial();
1090}
1091