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