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