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