First import
[xorg_rtime.git] / xorg-server-1.4 / Xext / security.c
blobba057defd3516b66c28a956429db993d14e6c7b5
1 /*
3 Copyright 1996, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
29 #endif
31 #include "dixstruct.h"
32 #include "extnsionst.h"
33 #include "windowstr.h"
34 #include "inputstr.h"
35 #include "scrnintstr.h"
36 #include "gcstruct.h"
37 #include "colormapst.h"
38 #include "propertyst.h"
39 #include "xacestr.h"
40 #include "securitysrv.h"
41 #include <X11/extensions/securstr.h>
42 #include <assert.h>
43 #include <stdarg.h>
44 #ifdef XAPPGROUP
45 #include "appgroup.h"
46 #endif
47 #include <stdio.h> /* for file reading operations */
48 #include <X11/Xatom.h> /* for XA_STRING */
50 #ifndef DEFAULTPOLICYFILE
51 # define DEFAULTPOLICYFILE NULL
52 #endif
53 #if defined(WIN32) || defined(__CYGWIN__)
54 #include <X11/Xos.h>
55 #undef index
56 #endif
58 #include "modinit.h"
60 static int SecurityErrorBase; /* first Security error number */
61 static int SecurityEventBase; /* first Security event number */
62 static int securityClientPrivateIndex;
63 static int securityExtnsnPrivateIndex;
65 /* this is what we store as client security state */
66 typedef struct {
67 unsigned int trustLevel;
68 XID authId;
69 } SecurityClientStateRec;
71 #define STATEVAL(extnsn) \
72 ((extnsn)->devPrivates[securityExtnsnPrivateIndex].val)
73 #define STATEPTR(client) \
74 ((client)->devPrivates[securityClientPrivateIndex].ptr)
75 #define TRUSTLEVEL(client) \
76 (((SecurityClientStateRec*)STATEPTR(client))->trustLevel)
77 #define AUTHID(client) \
78 (((SecurityClientStateRec*)STATEPTR(client))->authId)
80 static CallbackListPtr SecurityValidateGroupCallback = NULL;
82 RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */
84 static RESTYPE RTEventClient;
86 #define CALLBACK(name) static void \
87 name(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
89 /* SecurityAudit
91 * Arguments:
92 * format is the formatting string to be used to interpret the
93 * remaining arguments.
95 * Returns: nothing.
97 * Side Effects:
98 * Writes the message to the log file if security logging is on.
101 static void
102 SecurityAudit(char *format, ...)
104 va_list args;
106 if (auditTrailLevel < SECURITY_AUDIT_LEVEL)
107 return;
108 va_start(args, format);
109 VAuditF(format, args);
110 va_end(args);
111 } /* SecurityAudit */
113 #define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
115 /* SecurityDeleteAuthorization
117 * Arguments:
118 * value is the authorization to delete.
119 * id is its resource ID.
121 * Returns: Success.
123 * Side Effects:
124 * Frees everything associated with the authorization.
127 static int
128 SecurityDeleteAuthorization(
129 pointer value,
130 XID id)
132 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
133 unsigned short name_len, data_len;
134 char *name, *data;
135 int status;
136 int i;
137 OtherClientsPtr pEventClient;
139 /* Remove the auth using the os layer auth manager */
141 status = AuthorizationFromID(pAuth->id, &name_len, &name,
142 &data_len, &data);
143 assert(status);
144 status = RemoveAuthorization(name_len, name, data_len, data);
145 assert(status);
146 (void)status;
148 /* free the auth timer if there is one */
150 if (pAuth->timer) TimerFree(pAuth->timer);
152 /* send revoke events */
154 while ((pEventClient = pAuth->eventClients))
156 /* send revocation event event */
157 ClientPtr client = rClient(pEventClient);
159 if (!client->clientGone)
161 xSecurityAuthorizationRevokedEvent are;
162 are.type = SecurityEventBase + XSecurityAuthorizationRevoked;
163 are.sequenceNumber = client->sequence;
164 are.authId = pAuth->id;
165 WriteEventsToClient(client, 1, (xEvent *)&are);
167 FreeResource(pEventClient->resource, RT_NONE);
170 /* kill all clients using this auth */
172 for (i = 1; i<currentMaxClients; i++)
174 if (clients[i] && (AUTHID(clients[i]) == pAuth->id))
175 CloseDownClient(clients[i]);
178 SecurityAudit("revoked authorization ID %d\n", pAuth->id);
179 xfree(pAuth);
180 return Success;
182 } /* SecurityDeleteAuthorization */
185 /* resource delete function for RTEventClient */
186 static int
187 SecurityDeleteAuthorizationEventClient(
188 pointer value,
189 XID id)
191 OtherClientsPtr pEventClient, prev = NULL;
192 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
194 for (pEventClient = pAuth->eventClients;
195 pEventClient;
196 pEventClient = pEventClient->next)
198 if (pEventClient->resource == id)
200 if (prev)
201 prev->next = pEventClient->next;
202 else
203 pAuth->eventClients = pEventClient->next;
204 xfree(pEventClient);
205 return(Success);
207 prev = pEventClient;
209 /*NOTREACHED*/
210 return -1; /* make compiler happy */
211 } /* SecurityDeleteAuthorizationEventClient */
214 /* SecurityComputeAuthorizationTimeout
216 * Arguments:
217 * pAuth is the authorization for which we are computing the timeout
218 * seconds is the number of seconds we want to wait
220 * Returns:
221 * the number of milliseconds that the auth timer should be set to
223 * Side Effects:
224 * Sets pAuth->secondsRemaining to any "overflow" amount of time
225 * that didn't fit in 32 bits worth of milliseconds
228 static CARD32
229 SecurityComputeAuthorizationTimeout(
230 SecurityAuthorizationPtr pAuth,
231 unsigned int seconds)
233 /* maxSecs is the number of full seconds that can be expressed in
234 * 32 bits worth of milliseconds
236 CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND;
238 if (seconds > maxSecs)
239 { /* only come here if we want to wait more than 49 days */
240 pAuth->secondsRemaining = seconds - maxSecs;
241 return maxSecs * MILLI_PER_SECOND;
243 else
244 { /* by far the common case */
245 pAuth->secondsRemaining = 0;
246 return seconds * MILLI_PER_SECOND;
248 } /* SecurityStartAuthorizationTimer */
250 /* SecurityAuthorizationExpired
252 * This function is passed as an argument to TimerSet and gets called from
253 * the timer manager in the os layer when its time is up.
255 * Arguments:
256 * timer is the timer for this authorization.
257 * time is the current time.
258 * pval is the authorization whose time is up.
260 * Returns:
261 * A new time delay in milliseconds if the timer should wait some
262 * more, else zero.
264 * Side Effects:
265 * Frees the authorization resource if the timeout period is really
266 * over, otherwise recomputes pAuth->secondsRemaining.
269 static CARD32
270 SecurityAuthorizationExpired(
271 OsTimerPtr timer,
272 CARD32 time,
273 pointer pval)
275 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval;
277 assert(pAuth->timer == timer);
279 if (pAuth->secondsRemaining)
281 return SecurityComputeAuthorizationTimeout(pAuth,
282 pAuth->secondsRemaining);
284 else
286 FreeResource(pAuth->id, RT_NONE);
287 return 0;
289 } /* SecurityAuthorizationExpired */
291 /* SecurityStartAuthorizationTimer
293 * Arguments:
294 * pAuth is the authorization whose timer should be started.
296 * Returns: nothing.
298 * Side Effects:
299 * A timer is started, set to expire after the timeout period for
300 * this authorization. When it expires, the function
301 * SecurityAuthorizationExpired will be called.
304 static void
305 SecurityStartAuthorizationTimer(
306 SecurityAuthorizationPtr pAuth)
308 pAuth->timer = TimerSet(pAuth->timer, 0,
309 SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout),
310 SecurityAuthorizationExpired, pAuth);
311 } /* SecurityStartAuthorizationTimer */
314 /* Proc functions all take a client argument, execute the request in
315 * client->requestBuffer, and return a protocol error status.
318 static int
319 ProcSecurityQueryVersion(
320 ClientPtr client)
322 /* REQUEST(xSecurityQueryVersionReq); */
323 xSecurityQueryVersionReply rep;
325 /* paranoia: this "can't happen" because this extension is hidden
326 * from untrusted clients, but just in case...
328 if (TRUSTLEVEL(client) != XSecurityClientTrusted)
329 return BadRequest;
331 REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
332 rep.type = X_Reply;
333 rep.sequenceNumber = client->sequence;
334 rep.length = 0;
335 rep.majorVersion = SECURITY_MAJOR_VERSION;
336 rep.minorVersion = SECURITY_MINOR_VERSION;
337 if(client->swapped)
339 register char n;
340 swaps(&rep.sequenceNumber, n);
341 swaps(&rep.majorVersion, n);
342 swaps(&rep.minorVersion, n);
344 (void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply),
345 (char *)&rep);
346 return (client->noClientException);
347 } /* ProcSecurityQueryVersion */
350 static int
351 SecurityEventSelectForAuthorization(
352 SecurityAuthorizationPtr pAuth,
353 ClientPtr client,
354 Mask mask)
356 OtherClients *pEventClient;
358 for (pEventClient = pAuth->eventClients;
359 pEventClient;
360 pEventClient = pEventClient->next)
362 if (SameClient(pEventClient, client))
364 if (mask == 0)
365 FreeResource(pEventClient->resource, RT_NONE);
366 else
367 pEventClient->mask = mask;
368 return Success;
372 pEventClient = (OtherClients *) xalloc(sizeof(OtherClients));
373 if (!pEventClient)
374 return BadAlloc;
375 pEventClient->mask = mask;
376 pEventClient->resource = FakeClientID(client->index);
377 pEventClient->next = pAuth->eventClients;
378 if (!AddResource(pEventClient->resource, RTEventClient,
379 (pointer)pAuth))
381 xfree(pEventClient);
382 return BadAlloc;
384 pAuth->eventClients = pEventClient;
386 return Success;
387 } /* SecurityEventSelectForAuthorization */
390 static int
391 ProcSecurityGenerateAuthorization(
392 ClientPtr client)
394 REQUEST(xSecurityGenerateAuthorizationReq);
395 int len; /* request length in CARD32s*/
396 Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */
397 SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */
398 int err; /* error to return from this function */
399 XID authId; /* authorization ID assigned by os layer */
400 xSecurityGenerateAuthorizationReply rep; /* reply struct */
401 unsigned int trustLevel; /* trust level of new auth */
402 XID group; /* group of new auth */
403 CARD32 timeout; /* timeout of new auth */
404 CARD32 *values; /* list of supplied attributes */
405 char *protoname; /* auth proto name sent in request */
406 char *protodata; /* auth proto data sent in request */
407 unsigned int authdata_len; /* # bytes of generated auth data */
408 char *pAuthdata; /* generated auth data */
409 Mask eventMask; /* what events on this auth does client want */
411 /* paranoia: this "can't happen" because this extension is hidden
412 * from untrusted clients, but just in case...
414 if (TRUSTLEVEL(client) != XSecurityClientTrusted)
415 return BadRequest;
417 /* check request length */
419 REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
420 len = SIZEOF(xSecurityGenerateAuthorizationReq) >> 2;
421 len += (stuff->nbytesAuthProto + (unsigned)3) >> 2;
422 len += (stuff->nbytesAuthData + (unsigned)3) >> 2;
423 values = ((CARD32 *)stuff) + len;
424 len += Ones(stuff->valueMask);
425 if (client->req_len != len)
426 return BadLength;
428 /* check valuemask */
429 if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes)
431 client->errorValue = stuff->valueMask;
432 return BadValue;
435 /* check timeout */
436 timeout = 60;
437 if (stuff->valueMask & XSecurityTimeout)
439 timeout = *values++;
442 /* check trustLevel */
443 trustLevel = XSecurityClientUntrusted;
444 if (stuff->valueMask & XSecurityTrustLevel)
446 trustLevel = *values++;
447 if (trustLevel != XSecurityClientTrusted &&
448 trustLevel != XSecurityClientUntrusted)
450 client->errorValue = trustLevel;
451 return BadValue;
455 /* check group */
456 group = None;
457 if (stuff->valueMask & XSecurityGroup)
459 group = *values++;
460 if (SecurityValidateGroupCallback)
462 SecurityValidateGroupInfoRec vgi;
463 vgi.group = group;
464 vgi.valid = FALSE;
465 CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi);
467 /* if nobody said they recognized it, it's an error */
469 if (!vgi.valid)
471 client->errorValue = group;
472 return BadValue;
477 /* check event mask */
478 eventMask = 0;
479 if (stuff->valueMask & XSecurityEventMask)
481 eventMask = *values++;
482 if (eventMask & ~XSecurityAllEventMasks)
484 client->errorValue = eventMask;
485 return BadValue;
489 protoname = (char *)&stuff[1];
490 protodata = protoname + ((stuff->nbytesAuthProto + (unsigned)3) >> 2);
492 /* call os layer to generate the authorization */
494 authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname,
495 stuff->nbytesAuthData, protodata,
496 &authdata_len, &pAuthdata);
497 if ((XID) ~0L == authId)
499 err = SecurityErrorBase + XSecurityBadAuthorizationProtocol;
500 goto bailout;
503 /* now that we've added the auth, remember to remove it if we have to
504 * abort the request for some reason (like allocation failure)
506 removeAuth = TRUE;
508 /* associate additional information with this auth ID */
510 pAuth = (SecurityAuthorizationPtr)xalloc(sizeof(SecurityAuthorizationRec));
511 if (!pAuth)
513 err = BadAlloc;
514 goto bailout;
517 /* fill in the auth fields */
519 pAuth->id = authId;
520 pAuth->timeout = timeout;
521 pAuth->group = group;
522 pAuth->trustLevel = trustLevel;
523 pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */
524 pAuth->secondsRemaining = 0;
525 pAuth->timer = NULL;
526 pAuth->eventClients = NULL;
528 /* handle event selection */
529 if (eventMask)
531 err = SecurityEventSelectForAuthorization(pAuth, client, eventMask);
532 if (err != Success)
533 goto bailout;
536 if (!AddResource(authId, SecurityAuthorizationResType, pAuth))
538 err = BadAlloc;
539 goto bailout;
542 /* start the timer ticking */
544 if (pAuth->timeout != 0)
545 SecurityStartAuthorizationTimer(pAuth);
547 /* tell client the auth id and data */
549 rep.type = X_Reply;
550 rep.length = (authdata_len + 3) >> 2;
551 rep.sequenceNumber = client->sequence;
552 rep.authId = authId;
553 rep.dataLength = authdata_len;
555 if (client->swapped)
557 register char n;
558 swapl(&rep.length, n);
559 swaps(&rep.sequenceNumber, n);
560 swapl(&rep.authId, n);
561 swaps(&rep.dataLength, n);
564 WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply),
565 (char *)&rep);
566 WriteToClient(client, authdata_len, pAuthdata);
568 SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n",
569 client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout,
570 pAuth->group, eventMask);
572 /* the request succeeded; don't call RemoveAuthorization or free pAuth */
574 removeAuth = FALSE;
575 pAuth = NULL;
576 err = client->noClientException;
578 bailout:
579 if (removeAuth)
580 RemoveAuthorization(stuff->nbytesAuthProto, protoname,
581 authdata_len, pAuthdata);
582 if (pAuth) xfree(pAuth);
583 return err;
585 } /* ProcSecurityGenerateAuthorization */
587 static int
588 ProcSecurityRevokeAuthorization(
589 ClientPtr client)
591 REQUEST(xSecurityRevokeAuthorizationReq);
592 SecurityAuthorizationPtr pAuth;
594 /* paranoia: this "can't happen" because this extension is hidden
595 * from untrusted clients, but just in case...
597 if (TRUSTLEVEL(client) != XSecurityClientTrusted)
598 return BadRequest;
600 REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
602 pAuth = (SecurityAuthorizationPtr)SecurityLookupIDByType(client,
603 stuff->authId, SecurityAuthorizationResType, DixDestroyAccess);
604 if (!pAuth)
605 return SecurityErrorBase + XSecurityBadAuthorization;
607 FreeResource(stuff->authId, RT_NONE);
608 return Success;
609 } /* ProcSecurityRevokeAuthorization */
612 static int
613 ProcSecurityDispatch(
614 ClientPtr client)
616 REQUEST(xReq);
618 switch (stuff->data)
620 case X_SecurityQueryVersion:
621 return ProcSecurityQueryVersion(client);
622 case X_SecurityGenerateAuthorization:
623 return ProcSecurityGenerateAuthorization(client);
624 case X_SecurityRevokeAuthorization:
625 return ProcSecurityRevokeAuthorization(client);
626 default:
627 return BadRequest;
629 } /* ProcSecurityDispatch */
631 static int
632 SProcSecurityQueryVersion(
633 ClientPtr client)
635 REQUEST(xSecurityQueryVersionReq);
636 register char n;
638 swaps(&stuff->length, n);
639 REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
640 swaps(&stuff->majorVersion, n);
641 swaps(&stuff->minorVersion,n);
642 return ProcSecurityQueryVersion(client);
643 } /* SProcSecurityQueryVersion */
646 static int
647 SProcSecurityGenerateAuthorization(
648 ClientPtr client)
650 REQUEST(xSecurityGenerateAuthorizationReq);
651 register char n;
652 CARD32 *values;
653 unsigned long nvalues;
655 swaps(&stuff->length, n);
656 REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
657 swaps(&stuff->nbytesAuthProto, n);
658 swaps(&stuff->nbytesAuthData, n);
659 swapl(&stuff->valueMask, n);
660 values = (CARD32 *)(&stuff[1]) +
661 ((stuff->nbytesAuthProto + (unsigned)3) >> 2) +
662 ((stuff->nbytesAuthData + (unsigned)3) >> 2);
663 nvalues = (((CARD32 *)stuff) + stuff->length) - values;
664 SwapLongs(values, nvalues);
665 return ProcSecurityGenerateAuthorization(client);
666 } /* SProcSecurityGenerateAuthorization */
669 static int
670 SProcSecurityRevokeAuthorization(
671 ClientPtr client)
673 REQUEST(xSecurityRevokeAuthorizationReq);
674 register char n;
676 swaps(&stuff->length, n);
677 REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
678 swapl(&stuff->authId, n);
679 return ProcSecurityRevokeAuthorization(client);
680 } /* SProcSecurityRevokeAuthorization */
683 static int
684 SProcSecurityDispatch(
685 ClientPtr client)
687 REQUEST(xReq);
689 switch (stuff->data)
691 case X_SecurityQueryVersion:
692 return SProcSecurityQueryVersion(client);
693 case X_SecurityGenerateAuthorization:
694 return SProcSecurityGenerateAuthorization(client);
695 case X_SecurityRevokeAuthorization:
696 return SProcSecurityRevokeAuthorization(client);
697 default:
698 return BadRequest;
700 } /* SProcSecurityDispatch */
702 static void
703 SwapSecurityAuthorizationRevokedEvent(
704 xSecurityAuthorizationRevokedEvent *from,
705 xSecurityAuthorizationRevokedEvent *to)
707 to->type = from->type;
708 to->detail = from->detail;
709 cpswaps(from->sequenceNumber, to->sequenceNumber);
710 cpswapl(from->authId, to->authId);
713 /* SecurityDetermineEventPropogationLimits
715 * This is a helper function for SecurityCheckDeviceAccess.
717 * Arguments:
718 * dev is the device for which the starting and stopping windows for
719 * event propogation should be determined.
720 * The values pointed to by ppWin and ppStopWin are not used.
722 * Returns:
723 * ppWin is filled in with a pointer to the window at which event
724 * propogation for the given device should start given the current
725 * state of the server (pointer position, window layout, etc.)
726 * ppStopWin is filled in with the window at which event propogation
727 * should stop; events should not go to ppStopWin.
729 * Side Effects: none.
732 static void
733 SecurityDetermineEventPropogationLimits(
734 DeviceIntPtr dev,
735 WindowPtr *ppWin,
736 WindowPtr *ppStopWin)
738 WindowPtr pFocusWin = dev->focus ? dev->focus->win : NoneWin;
740 if (pFocusWin == NoneWin)
741 { /* no focus -- events don't go anywhere */
742 *ppWin = *ppStopWin = NULL;
743 return;
746 if (pFocusWin == PointerRootWin)
747 { /* focus follows the pointer */
748 *ppWin = GetSpriteWindow();
749 *ppStopWin = NULL; /* propogate all the way to the root */
751 else
752 { /* a real window is set for the focus */
753 WindowPtr pSpriteWin = GetSpriteWindow();
754 *ppStopWin = pFocusWin->parent; /* don't go past the focus window */
756 /* if the pointer is in a subwindow of the focus window, start
757 * at that subwindow, else start at the focus window itself
759 if (IsParent(pFocusWin, pSpriteWin))
760 *ppWin = pSpriteWin;
761 else *ppWin = pFocusWin;
763 } /* SecurityDetermineEventPropogationLimits */
766 /* SecurityCheckDeviceAccess
768 * Arguments:
769 * client is the client attempting to access a device.
770 * dev is the device being accessed.
771 * fromRequest is TRUE if the device access is a direct result of
772 * the client executing some request and FALSE if it is a
773 * result of the server trying to send an event (e.g. KeymapNotify)
774 * to the client.
775 * Returns:
776 * TRUE if the device access should be allowed, else FALSE.
778 * Side Effects:
779 * An audit message is generated if access is denied.
782 CALLBACK(SecurityCheckDeviceAccess)
784 XaceDeviceAccessRec *rec = (XaceDeviceAccessRec*)calldata;
785 ClientPtr client = rec->client;
786 DeviceIntPtr dev = rec->dev;
787 Bool fromRequest = rec->fromRequest;
788 WindowPtr pWin, pStopWin;
789 Bool untrusted_got_event;
790 Bool found_event_window;
791 Mask eventmask;
792 int reqtype = 0;
794 /* trusted clients always allowed to do anything */
795 if (TRUSTLEVEL(client) == XSecurityClientTrusted)
796 return;
798 /* device security other than keyboard is not implemented yet */
799 if (dev != inputInfo.keyboard)
800 return;
802 /* some untrusted client wants access */
804 if (fromRequest)
806 reqtype = ((xReq *)client->requestBuffer)->reqType;
807 switch (reqtype)
809 /* never allow these */
810 case X_ChangeKeyboardMapping:
811 case X_ChangeKeyboardControl:
812 case X_SetModifierMapping:
813 SecurityAudit("client %d attempted request %d\n",
814 client->index, reqtype);
815 rec->rval = FALSE;
816 return;
817 default:
818 break;
822 untrusted_got_event = FALSE;
823 found_event_window = FALSE;
825 if (dev->grab)
827 untrusted_got_event =
828 (TRUSTLEVEL(rClient(dev->grab)) != XSecurityClientTrusted);
830 else
832 SecurityDetermineEventPropogationLimits(dev, &pWin, &pStopWin);
834 eventmask = KeyPressMask | KeyReleaseMask;
835 while ( (pWin != pStopWin) && !found_event_window)
837 OtherClients *other;
839 if (pWin->eventMask & eventmask)
841 found_event_window = TRUE;
842 client = wClient(pWin);
843 if (TRUSTLEVEL(client) != XSecurityClientTrusted)
845 untrusted_got_event = TRUE;
848 if (wOtherEventMasks(pWin) & eventmask)
850 found_event_window = TRUE;
851 for (other = wOtherClients(pWin); other; other = other->next)
853 if (other->mask & eventmask)
855 client = rClient(other);
856 if (TRUSTLEVEL(client) != XSecurityClientTrusted)
858 untrusted_got_event = TRUE;
859 break;
864 if (wDontPropagateMask(pWin) & eventmask)
865 break;
866 pWin = pWin->parent;
867 } /* while propogating the event */
870 /* allow access by untrusted clients only if an event would have gone
871 * to an untrusted client
874 if (!untrusted_got_event)
876 char *devname = dev->name;
877 if (!devname) devname = "unnamed";
878 if (fromRequest)
879 SecurityAudit("client %d attempted request %d device %d (%s)\n",
880 client->index, reqtype, dev->id, devname);
881 else
882 SecurityAudit("client %d attempted to access device %d (%s)\n",
883 client->index, dev->id, devname);
884 rec->rval = FALSE;
886 return;
887 } /* SecurityCheckDeviceAccess */
891 /* SecurityAuditResourceIDAccess
893 * Arguments:
894 * client is the client doing the resource access.
895 * id is the resource id.
897 * Returns: NULL
899 * Side Effects:
900 * An audit message is generated with details of the denied
901 * resource access.
904 static pointer
905 SecurityAuditResourceIDAccess(
906 ClientPtr client,
907 XID id)
909 int cid = CLIENT_ID(id);
910 int reqtype = ((xReq *)client->requestBuffer)->reqType;
911 switch (reqtype)
913 case X_ChangeProperty:
914 case X_DeleteProperty:
915 case X_GetProperty:
917 xChangePropertyReq *req =
918 (xChangePropertyReq *)client->requestBuffer;
919 int propertyatom = req->property;
920 char *propertyname = NameForAtom(propertyatom);
922 SecurityAudit("client %d attempted request %d with window 0x%x property %s of client %d\n",
923 client->index, reqtype, id, propertyname, cid);
924 break;
926 default:
928 SecurityAudit("client %d attempted request %d with resource 0x%x of client %d\n",
929 client->index, reqtype, id, cid);
930 break;
933 return NULL;
934 } /* SecurityAuditResourceIDAccess */
937 /* SecurityCheckResourceIDAccess
939 * This function gets plugged into client->CheckAccess and is called from
940 * SecurityLookupIDByType/Class to determine if the client can access the
941 * resource.
943 * Arguments:
944 * client is the client doing the resource access.
945 * id is the resource id.
946 * rtype is its type or class.
947 * access_mode represents the intended use of the resource; see
948 * resource.h.
949 * res is a pointer to the resource structure for this resource.
951 * Returns:
952 * If access is granted, the value of rval that was passed in, else FALSE.
954 * Side Effects:
955 * Disallowed resource accesses are audited.
958 CALLBACK(SecurityCheckResourceIDAccess)
960 XaceResourceAccessRec *rec = (XaceResourceAccessRec*)calldata;
961 ClientPtr client = rec->client;
962 XID id = rec->id;
963 RESTYPE rtype = rec->rtype;
964 Mask access_mode = rec->access_mode;
965 pointer rval = rec->res;
966 int cid, reqtype;
968 if (TRUSTLEVEL(client) == XSecurityClientTrusted ||
969 DixUnknownAccess == access_mode)
970 return; /* for compatibility, we have to allow access */
972 cid = CLIENT_ID(id);
973 reqtype = ((xReq *)client->requestBuffer)->reqType;
974 switch (reqtype)
975 { /* these are always allowed */
976 case X_QueryTree:
977 case X_TranslateCoords:
978 case X_GetGeometry:
979 /* property access is controlled in SecurityCheckPropertyAccess */
980 case X_GetProperty:
981 case X_ChangeProperty:
982 case X_DeleteProperty:
983 case X_RotateProperties:
984 case X_ListProperties:
985 return;
986 default:
987 break;
990 if (cid != 0)
991 { /* not a server-owned resource */
993 * The following 'if' restricts clients to only access resources at
994 * the same trustLevel. Since there are currently only two trust levels,
995 * and trusted clients never call this function, this degenerates into
996 * saying that untrusted clients can only access resources of other
997 * untrusted clients. One way to add the notion of groups would be to
998 * allow values other than Trusted (0) and Untrusted (1) for this field.
999 * Clients at the same trust level would be able to use each other's
1000 * resources, but not those of clients at other trust levels. I haven't
1001 * tried it, but this probably mostly works already. The obvious
1002 * competing alternative for grouping clients for security purposes is to
1003 * use app groups. dpw
1005 if (TRUSTLEVEL(client) == TRUSTLEVEL(clients[cid])
1006 #ifdef XAPPGROUP
1007 || (RT_COLORMAP == rtype &&
1008 XagDefaultColormap (client) == (Colormap) id)
1009 #endif
1011 return;
1012 else
1013 goto deny;
1015 else /* server-owned resource - probably a default colormap or root window */
1017 if (RT_WINDOW == rtype || RC_DRAWABLE == rtype)
1019 switch (reqtype)
1020 { /* the following operations are allowed on root windows */
1021 case X_CreatePixmap:
1022 case X_CreateGC:
1023 case X_CreateWindow:
1024 case X_CreateColormap:
1025 case X_ListProperties:
1026 case X_GrabPointer:
1027 case X_UngrabButton:
1028 case X_QueryBestSize:
1029 case X_GetWindowAttributes:
1030 break;
1031 case X_SendEvent:
1032 { /* see if it is an event specified by the ICCCM */
1033 xSendEventReq *req = (xSendEventReq *)
1034 (client->requestBuffer);
1035 if (req->propagate == xTrue
1037 (req->eventMask != ColormapChangeMask &&
1038 req->eventMask != StructureNotifyMask &&
1039 req->eventMask !=
1040 (SubstructureRedirectMask|SubstructureNotifyMask)
1043 (req->event.u.u.type != UnmapNotify &&
1044 req->event.u.u.type != ConfigureRequest &&
1045 req->event.u.u.type != ClientMessage
1048 { /* not an ICCCM event */
1049 goto deny;
1051 break;
1052 } /* case X_SendEvent on root */
1054 case X_ChangeWindowAttributes:
1055 { /* Allow selection of PropertyNotify and StructureNotify
1056 * events on the root.
1058 xChangeWindowAttributesReq *req =
1059 (xChangeWindowAttributesReq *)(client->requestBuffer);
1060 if (req->valueMask == CWEventMask)
1062 CARD32 value = *((CARD32 *)(req + 1));
1063 if ( (value &
1064 ~(PropertyChangeMask|StructureNotifyMask)) == 0)
1065 break;
1067 goto deny;
1068 } /* case X_ChangeWindowAttributes on root */
1070 default:
1072 /* others not allowed */
1073 goto deny;
1076 } /* end server-owned window or drawable */
1077 else if (SecurityAuthorizationResType == rtype)
1079 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)rval;
1080 if (pAuth->trustLevel != TRUSTLEVEL(client))
1081 goto deny;
1083 else if (RT_COLORMAP != rtype)
1084 { /* don't allow anything else besides colormaps */
1085 goto deny;
1088 return;
1089 deny:
1090 SecurityAuditResourceIDAccess(client, id);
1091 rec->rval = FALSE; /* deny access */
1092 } /* SecurityCheckResourceIDAccess */
1095 /* SecurityClientStateCallback
1097 * Arguments:
1098 * pcbl is &ClientStateCallback.
1099 * nullata is NULL.
1100 * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
1101 * which contains information about client state changes.
1103 * Returns: nothing.
1105 * Side Effects:
1107 * If a new client is connecting, its authorization ID is copied to
1108 * client->authID. If this is a generated authorization, its reference
1109 * count is bumped, its timer is cancelled if it was running, and its
1110 * trustlevel is copied to TRUSTLEVEL(client).
1112 * If a client is disconnecting and the client was using a generated
1113 * authorization, the authorization's reference count is decremented, and
1114 * if it is now zero, the timer for this authorization is started.
1117 CALLBACK(SecurityClientStateCallback)
1119 NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
1120 ClientPtr client = pci->client;
1122 switch (client->clientState)
1124 case ClientStateInitial:
1125 TRUSTLEVEL(client) = XSecurityClientTrusted;
1126 AUTHID(client) = None;
1127 break;
1129 case ClientStateRunning:
1131 XID authId = AuthorizationIDOfClient(client);
1132 SecurityAuthorizationPtr pAuth;
1134 TRUSTLEVEL(client) = XSecurityClientTrusted;
1135 AUTHID(client) = authId;
1136 pAuth = (SecurityAuthorizationPtr)LookupIDByType(authId,
1137 SecurityAuthorizationResType);
1138 if (pAuth)
1139 { /* it is a generated authorization */
1140 pAuth->refcnt++;
1141 if (pAuth->refcnt == 1)
1143 if (pAuth->timer) TimerCancel(pAuth->timer);
1145 TRUSTLEVEL(client) = pAuth->trustLevel;
1147 break;
1149 case ClientStateGone:
1150 case ClientStateRetained: /* client disconnected */
1152 SecurityAuthorizationPtr pAuth;
1154 /* client may not have any state (bad authorization) */
1155 if (!STATEPTR(client))
1156 break;
1158 pAuth = (SecurityAuthorizationPtr)LookupIDByType(AUTHID(client),
1159 SecurityAuthorizationResType);
1160 if (pAuth)
1161 { /* it is a generated authorization */
1162 pAuth->refcnt--;
1163 if (pAuth->refcnt == 0)
1165 SecurityStartAuthorizationTimer(pAuth);
1168 break;
1170 default: break;
1172 } /* SecurityClientStateCallback */
1174 CALLBACK(SecurityCheckDrawableAccess)
1176 XaceDrawableAccessRec *rec = (XaceDrawableAccessRec*)calldata;
1178 if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted)
1179 rec->rval = FALSE;
1182 CALLBACK(SecurityCheckMapAccess)
1184 XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata;
1185 WindowPtr pWin = rec->pWin;
1187 if (STATEPTR(rec->client) &&
1188 (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) &&
1189 (pWin->drawable.class == InputOnly) &&
1190 pWin->parent && pWin->parent->parent &&
1191 (TRUSTLEVEL(wClient(pWin->parent)) == XSecurityClientTrusted))
1193 rec->rval = FALSE;
1196 CALLBACK(SecurityCheckBackgrndAccess)
1198 XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata;
1200 if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted)
1201 rec->rval = FALSE;
1204 CALLBACK(SecurityCheckExtAccess)
1206 XaceExtAccessRec *rec = (XaceExtAccessRec*)calldata;
1208 if ((TRUSTLEVEL(rec->client) != XSecurityClientTrusted) &&
1209 !STATEVAL(rec->ext))
1211 rec->rval = FALSE;
1214 CALLBACK(SecurityCheckHostlistAccess)
1216 XaceHostlistAccessRec *rec = (XaceHostlistAccessRec*)calldata;
1218 if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted)
1220 rec->rval = FALSE;
1221 if (rec->access_mode == DixWriteAccess)
1222 SecurityAudit("client %d attempted to change host access\n",
1223 rec->client->index);
1224 else
1225 SecurityAudit("client %d attempted to list hosts\n",
1226 rec->client->index);
1230 CALLBACK(SecurityDeclareExtSecure)
1232 XaceDeclareExtSecureRec *rec = (XaceDeclareExtSecureRec*)calldata;
1234 /* security state for extensions is simply a boolean trust value */
1235 STATEVAL(rec->ext) = rec->secure;
1238 /**********************************************************************/
1240 typedef struct _PropertyAccessRec {
1241 ATOM name;
1242 ATOM mustHaveProperty;
1243 char *mustHaveValue;
1244 char windowRestriction;
1245 #define SecurityAnyWindow 0
1246 #define SecurityRootWindow 1
1247 #define SecurityWindowWithProperty 2
1248 char readAction;
1249 char writeAction;
1250 char destroyAction;
1251 struct _PropertyAccessRec *next;
1252 } PropertyAccessRec, *PropertyAccessPtr;
1254 static PropertyAccessPtr PropertyAccessList = NULL;
1255 static char SecurityDefaultAction = XaceErrorOperation;
1256 static char *SecurityPolicyFile = DEFAULTPOLICYFILE;
1257 static ATOM SecurityMaxPropertyName = 0;
1259 static char *SecurityKeywords[] = {
1260 #define SecurityKeywordComment 0
1261 "#",
1262 #define SecurityKeywordProperty 1
1263 "property",
1264 #define SecurityKeywordSitePolicy 2
1265 "sitepolicy",
1266 #define SecurityKeywordRoot 3
1267 "root",
1268 #define SecurityKeywordAny 4
1269 "any"
1272 #define NUMKEYWORDS (sizeof(SecurityKeywords) / sizeof(char *))
1274 #undef PROPDEBUG
1275 /*#define PROPDEBUG 1*/
1277 static void
1278 SecurityFreePropertyAccessList(void)
1280 while (PropertyAccessList)
1282 PropertyAccessPtr freeit = PropertyAccessList;
1283 PropertyAccessList = PropertyAccessList->next;
1284 xfree(freeit);
1286 } /* SecurityFreePropertyAccessList */
1288 #define SecurityIsWhitespace(c) ( (c == ' ') || (c == '\t') || (c == '\n') )
1290 static char *
1291 SecuritySkipWhitespace(
1292 char *p)
1294 while (SecurityIsWhitespace(*p))
1295 p++;
1296 return p;
1297 } /* SecuritySkipWhitespace */
1300 static char *
1301 SecurityParseString(
1302 char **rest)
1304 char *startOfString;
1305 char *s = *rest;
1306 char endChar = 0;
1308 s = SecuritySkipWhitespace(s);
1310 if (*s == '"' || *s == '\'')
1312 endChar = *s++;
1313 startOfString = s;
1314 while (*s && (*s != endChar))
1315 s++;
1317 else
1319 startOfString = s;
1320 while (*s && !SecurityIsWhitespace(*s))
1321 s++;
1323 if (*s)
1325 *s = '\0';
1326 *rest = s + 1;
1327 return startOfString;
1329 else
1331 *rest = s;
1332 return (endChar) ? NULL : startOfString;
1334 } /* SecurityParseString */
1337 static int
1338 SecurityParseKeyword(
1339 char **p)
1341 int i;
1342 char *s = *p;
1343 s = SecuritySkipWhitespace(s);
1344 for (i = 0; i < NUMKEYWORDS; i++)
1346 int len = strlen(SecurityKeywords[i]);
1347 if (strncmp(s, SecurityKeywords[i], len) == 0)
1349 *p = s + len;
1350 return (i);
1353 *p = s;
1354 return -1;
1355 } /* SecurityParseKeyword */
1358 static Bool
1359 SecurityParsePropertyAccessRule(
1360 char *p)
1362 char *propname;
1363 char c;
1364 char action = SecurityDefaultAction;
1365 char readAction, writeAction, destroyAction;
1366 PropertyAccessPtr pacl, prev, cur;
1367 char *mustHaveProperty = NULL;
1368 char *mustHaveValue = NULL;
1369 Bool invalid;
1370 char windowRestriction;
1371 int size;
1372 int keyword;
1374 /* get property name */
1375 propname = SecurityParseString(&p);
1376 if (!propname || (strlen(propname) == 0))
1377 return FALSE;
1379 /* get window on which property must reside for rule to apply */
1381 keyword = SecurityParseKeyword(&p);
1382 if (keyword == SecurityKeywordRoot)
1383 windowRestriction = SecurityRootWindow;
1384 else if (keyword == SecurityKeywordAny)
1385 windowRestriction = SecurityAnyWindow;
1386 else /* not root or any, must be a property name */
1388 mustHaveProperty = SecurityParseString(&p);
1389 if (!mustHaveProperty || (strlen(mustHaveProperty) == 0))
1390 return FALSE;
1391 windowRestriction = SecurityWindowWithProperty;
1392 p = SecuritySkipWhitespace(p);
1393 if (*p == '=')
1394 { /* property value is specified too */
1395 p++; /* skip over '=' */
1396 mustHaveValue = SecurityParseString(&p);
1397 if (!mustHaveValue)
1398 return FALSE;
1402 /* get operations and actions */
1404 invalid = FALSE;
1405 readAction = writeAction = destroyAction = SecurityDefaultAction;
1406 while ( (c = *p++) && !invalid)
1408 switch (c)
1410 case 'i': action = XaceIgnoreOperation; break;
1411 case 'a': action = XaceAllowOperation; break;
1412 case 'e': action = XaceErrorOperation; break;
1414 case 'r': readAction = action; break;
1415 case 'w': writeAction = action; break;
1416 case 'd': destroyAction = action; break;
1418 default :
1419 if (!SecurityIsWhitespace(c))
1420 invalid = TRUE;
1421 break;
1424 if (invalid)
1425 return FALSE;
1427 /* We've successfully collected all the information needed for this
1428 * property access rule. Now record it in a PropertyAccessRec.
1430 size = sizeof(PropertyAccessRec);
1432 /* If there is a property value string, allocate space for it
1433 * right after the PropertyAccessRec.
1435 if (mustHaveValue)
1436 size += strlen(mustHaveValue) + 1;
1437 pacl = (PropertyAccessPtr)Xalloc(size);
1438 if (!pacl)
1439 return FALSE;
1441 pacl->name = MakeAtom(propname, strlen(propname), TRUE);
1442 if (pacl->name == BAD_RESOURCE)
1444 Xfree(pacl);
1445 return FALSE;
1447 if (mustHaveProperty)
1449 pacl->mustHaveProperty = MakeAtom(mustHaveProperty,
1450 strlen(mustHaveProperty), TRUE);
1451 if (pacl->mustHaveProperty == BAD_RESOURCE)
1453 Xfree(pacl);
1454 return FALSE;
1457 else
1458 pacl->mustHaveProperty = 0;
1460 if (mustHaveValue)
1462 pacl->mustHaveValue = (char *)(pacl + 1);
1463 strcpy(pacl->mustHaveValue, mustHaveValue);
1465 else
1466 pacl->mustHaveValue = NULL;
1468 SecurityMaxPropertyName = max(SecurityMaxPropertyName, pacl->name);
1470 pacl->windowRestriction = windowRestriction;
1471 pacl->readAction = readAction;
1472 pacl->writeAction = writeAction;
1473 pacl->destroyAction = destroyAction;
1475 /* link the new rule into the list of rules in order of increasing
1476 * property name (atom) value to make searching easier
1479 for (prev = NULL, cur = PropertyAccessList;
1480 cur && cur->name <= pacl->name;
1481 prev = cur, cur = cur->next)
1483 if (!prev)
1485 pacl->next = cur;
1486 PropertyAccessList = pacl;
1488 else
1490 prev->next = pacl;
1491 pacl->next = cur;
1493 return TRUE;
1494 } /* SecurityParsePropertyAccessRule */
1496 static char **SecurityPolicyStrings = NULL;
1497 static int nSecurityPolicyStrings = 0;
1499 static Bool
1500 SecurityParseSitePolicy(
1501 char *p)
1503 char *policyStr = SecurityParseString(&p);
1504 char *copyPolicyStr;
1505 char **newStrings;
1507 if (!policyStr)
1508 return FALSE;
1510 copyPolicyStr = (char *)Xalloc(strlen(policyStr) + 1);
1511 if (!copyPolicyStr)
1512 return TRUE;
1513 strcpy(copyPolicyStr, policyStr);
1514 newStrings = (char **)Xrealloc(SecurityPolicyStrings,
1515 sizeof (char *) * (nSecurityPolicyStrings + 1));
1516 if (!newStrings)
1518 Xfree(copyPolicyStr);
1519 return TRUE;
1522 SecurityPolicyStrings = newStrings;
1523 SecurityPolicyStrings[nSecurityPolicyStrings++] = copyPolicyStr;
1525 return TRUE;
1527 } /* SecurityParseSitePolicy */
1530 char **
1531 SecurityGetSitePolicyStrings(n)
1532 int *n;
1534 *n = nSecurityPolicyStrings;
1535 return SecurityPolicyStrings;
1536 } /* SecurityGetSitePolicyStrings */
1538 static void
1539 SecurityFreeSitePolicyStrings(void)
1541 if (SecurityPolicyStrings)
1543 assert(nSecurityPolicyStrings);
1544 while (nSecurityPolicyStrings--)
1546 Xfree(SecurityPolicyStrings[nSecurityPolicyStrings]);
1548 Xfree(SecurityPolicyStrings);
1549 SecurityPolicyStrings = NULL;
1550 nSecurityPolicyStrings = 0;
1552 } /* SecurityFreeSitePolicyStrings */
1555 static void
1556 SecurityLoadPropertyAccessList(void)
1558 FILE *f;
1559 int lineNumber = 0;
1561 SecurityMaxPropertyName = 0;
1563 if (!SecurityPolicyFile)
1564 return;
1566 f = fopen(SecurityPolicyFile, "r");
1567 if (!f)
1569 ErrorF("error opening security policy file %s\n",
1570 SecurityPolicyFile);
1571 return;
1574 while (!feof(f))
1576 char buf[200];
1577 Bool validLine;
1578 char *p;
1580 if (!(p = fgets(buf, sizeof(buf), f)))
1581 break;
1582 lineNumber++;
1584 /* if first line, check version number */
1585 if (lineNumber == 1)
1587 char *v = SecurityParseString(&p);
1588 if (strcmp(v, SECURITY_POLICY_FILE_VERSION) != 0)
1590 ErrorF("%s: invalid security policy file version, ignoring file\n",
1591 SecurityPolicyFile);
1592 break;
1594 validLine = TRUE;
1596 else
1598 switch (SecurityParseKeyword(&p))
1600 case SecurityKeywordComment:
1601 validLine = TRUE;
1602 break;
1604 case SecurityKeywordProperty:
1605 validLine = SecurityParsePropertyAccessRule(p);
1606 break;
1608 case SecurityKeywordSitePolicy:
1609 validLine = SecurityParseSitePolicy(p);
1610 break;
1612 default:
1613 validLine = (*p == '\0'); /* blank lines OK, others not */
1614 break;
1618 if (!validLine)
1619 ErrorF("Line %d of %s invalid, ignoring\n",
1620 lineNumber, SecurityPolicyFile);
1621 } /* end while more input */
1623 #ifdef PROPDEBUG
1625 PropertyAccessPtr pacl;
1626 char *op = "aie";
1627 for (pacl = PropertyAccessList; pacl; pacl = pacl->next)
1629 ErrorF("property %s ", NameForAtom(pacl->name));
1630 switch (pacl->windowRestriction)
1632 case SecurityAnyWindow: ErrorF("any "); break;
1633 case SecurityRootWindow: ErrorF("root "); break;
1634 case SecurityWindowWithProperty:
1636 ErrorF("%s ", NameForAtom(pacl->mustHaveProperty));
1637 if (pacl->mustHaveValue)
1638 ErrorF(" = \"%s\" ", pacl->mustHaveValue);
1641 break;
1643 ErrorF("%cr %cw %cd\n", op[pacl->readAction],
1644 op[pacl->writeAction], op[pacl->destroyAction]);
1647 #endif /* PROPDEBUG */
1649 fclose(f);
1650 } /* SecurityLoadPropertyAccessList */
1653 static Bool
1654 SecurityMatchString(
1655 char *ws,
1656 char *cs)
1658 while (*ws && *cs)
1660 if (*ws == '*')
1662 Bool match = FALSE;
1663 ws++;
1664 while (!(match = SecurityMatchString(ws, cs)) && *cs)
1666 cs++;
1668 return match;
1670 else if (*ws == *cs)
1672 ws++;
1673 cs++;
1675 else break;
1677 return ( ( (*ws == '\0') || ((*ws == '*') && *(ws+1) == '\0') )
1678 && (*cs == '\0') );
1679 } /* SecurityMatchString */
1681 #ifdef PROPDEBUG
1682 #include <sys/types.h>
1683 #include <sys/stat.h>
1684 #endif
1687 CALLBACK(SecurityCheckPropertyAccess)
1689 XacePropertyAccessRec *rec = (XacePropertyAccessRec*)calldata;
1690 ClientPtr client = rec->client;
1691 WindowPtr pWin = rec->pWin;
1692 ATOM propertyName = rec->propertyName;
1693 Mask access_mode = rec->access_mode;
1694 PropertyAccessPtr pacl;
1695 char action = SecurityDefaultAction;
1697 /* if client trusted or window untrusted, allow operation */
1699 if ( (TRUSTLEVEL(client) == XSecurityClientTrusted) ||
1700 (TRUSTLEVEL(wClient(pWin)) != XSecurityClientTrusted) )
1701 return;
1703 #ifdef PROPDEBUG
1704 /* For testing, it's more convenient if the property rules file gets
1705 * reloaded whenever it changes, so we can rapidly try things without
1706 * having to reset the server.
1709 struct stat buf;
1710 static time_t lastmod = 0;
1711 int ret = stat(SecurityPolicyFile , &buf);
1712 if ( (ret == 0) && (buf.st_mtime > lastmod) )
1714 ErrorF("reloading property rules\n");
1715 SecurityFreePropertyAccessList();
1716 SecurityLoadPropertyAccessList();
1717 lastmod = buf.st_mtime;
1720 #endif
1722 /* If the property atom is bigger than any atoms on the list,
1723 * we know we won't find it, so don't even bother looking.
1725 if (propertyName <= SecurityMaxPropertyName)
1727 /* untrusted client operating on trusted window; see if it's allowed */
1729 for (pacl = PropertyAccessList; pacl; pacl = pacl->next)
1731 if (pacl->name < propertyName)
1732 continue;
1733 if (pacl->name > propertyName)
1734 break;
1736 /* pacl->name == propertyName, so see if it applies to this window */
1738 switch (pacl->windowRestriction)
1740 case SecurityAnyWindow: /* always applies */
1741 break;
1743 case SecurityRootWindow:
1745 /* if not a root window, this rule doesn't apply */
1746 if (pWin->parent)
1747 continue;
1749 break;
1751 case SecurityWindowWithProperty:
1753 PropertyPtr pProp = wUserProps (pWin);
1754 Bool match = FALSE;
1755 char *p;
1756 char *pEndData;
1758 while (pProp)
1760 if (pProp->propertyName == pacl->mustHaveProperty)
1761 break;
1762 pProp = pProp->next;
1764 if (!pProp)
1765 continue;
1766 if (!pacl->mustHaveValue)
1767 break;
1768 if (pProp->type != XA_STRING || pProp->format != 8)
1769 continue;
1771 p = pProp->data;
1772 pEndData = ((char *)pProp->data) + pProp->size;
1773 while (!match && p < pEndData)
1775 if (SecurityMatchString(pacl->mustHaveValue, p))
1776 match = TRUE;
1777 else
1778 { /* skip to the next string */
1779 while (*p++ && p < pEndData)
1783 if (!match)
1784 continue;
1786 break; /* end case SecurityWindowWithProperty */
1787 } /* end switch on windowRestriction */
1789 /* If we get here, the property access rule pacl applies.
1790 * If pacl doesn't apply, something above should have
1791 * executed a continue, which will skip the follwing code.
1793 action = XaceAllowOperation;
1794 if (access_mode & DixReadAccess)
1795 action = max(action, pacl->readAction);
1796 if (access_mode & DixWriteAccess)
1797 action = max(action, pacl->writeAction);
1798 if (access_mode & DixDestroyAccess)
1799 action = max(action, pacl->destroyAction);
1800 break;
1801 } /* end for each pacl */
1802 } /* end if propertyName <= SecurityMaxPropertyName */
1804 if (XaceAllowOperation != action)
1805 { /* audit the access violation */
1806 int cid = CLIENT_ID(pWin->drawable.id);
1807 int reqtype = ((xReq *)client->requestBuffer)->reqType;
1808 char *actionstr = (XaceIgnoreOperation == action) ?
1809 "ignored" : "error";
1810 SecurityAudit("client %d attempted request %d with window 0x%x property %s (atom 0x%x) of client %d, %s\n",
1811 client->index, reqtype, pWin->drawable.id,
1812 NameForAtom(propertyName), propertyName, cid, actionstr);
1814 /* return codes increase with strictness */
1815 if (action > rec->rval)
1816 rec->rval = action;
1817 } /* SecurityCheckPropertyAccess */
1820 /* SecurityResetProc
1822 * Arguments:
1823 * extEntry is the extension information for the security extension.
1825 * Returns: nothing.
1827 * Side Effects:
1828 * Performs any cleanup needed by Security at server shutdown time.
1831 static void
1832 SecurityResetProc(
1833 ExtensionEntry *extEntry)
1835 SecurityFreePropertyAccessList();
1836 SecurityFreeSitePolicyStrings();
1837 } /* SecurityResetProc */
1841 XSecurityOptions(argc, argv, i)
1842 int argc;
1843 char **argv;
1844 int i;
1846 if (strcmp(argv[i], "-sp") == 0)
1848 if (i < argc)
1849 SecurityPolicyFile = argv[++i];
1850 return (i + 1);
1852 return (i);
1853 } /* XSecurityOptions */
1856 /* SecurityExtensionSetup
1858 * Arguments: none.
1860 * Returns: nothing.
1862 * Side Effects:
1863 * Sets up the Security extension if possible.
1864 * This function contains things that need to be done
1865 * before any other extension init functions get called.
1868 void
1869 SecurityExtensionSetup(INITARGS)
1871 /* Allocate the client private index */
1872 securityClientPrivateIndex = AllocateClientPrivateIndex();
1873 if (!AllocateClientPrivate(securityClientPrivateIndex,
1874 sizeof (SecurityClientStateRec)))
1875 FatalError("SecurityExtensionSetup: Can't allocate client private.\n");
1877 /* Allocate the extension private index */
1878 securityExtnsnPrivateIndex = AllocateExtensionPrivateIndex();
1879 if (!AllocateExtensionPrivate(securityExtnsnPrivateIndex, 0))
1880 FatalError("SecurityExtensionSetup: Can't allocate extnsn private.\n");
1882 /* register callbacks */
1883 #define XaceRC XaceRegisterCallback
1884 XaceRC(XACE_RESOURCE_ACCESS, SecurityCheckResourceIDAccess, NULL);
1885 XaceRC(XACE_DEVICE_ACCESS, SecurityCheckDeviceAccess, NULL);
1886 XaceRC(XACE_PROPERTY_ACCESS, SecurityCheckPropertyAccess, NULL);
1887 XaceRC(XACE_DRAWABLE_ACCESS, SecurityCheckDrawableAccess, NULL);
1888 XaceRC(XACE_MAP_ACCESS, SecurityCheckMapAccess, NULL);
1889 XaceRC(XACE_BACKGRND_ACCESS, SecurityCheckBackgrndAccess, NULL);
1890 XaceRC(XACE_EXT_DISPATCH, SecurityCheckExtAccess, NULL);
1891 XaceRC(XACE_EXT_ACCESS, SecurityCheckExtAccess, NULL);
1892 XaceRC(XACE_HOSTLIST_ACCESS, SecurityCheckHostlistAccess, NULL);
1893 XaceRC(XACE_DECLARE_EXT_SECURE, SecurityDeclareExtSecure, NULL);
1894 } /* SecurityExtensionSetup */
1897 /* SecurityExtensionInit
1899 * Arguments: none.
1901 * Returns: nothing.
1903 * Side Effects:
1904 * Enables the Security extension if possible.
1907 void
1908 SecurityExtensionInit(INITARGS)
1910 ExtensionEntry *extEntry;
1912 SecurityAuthorizationResType =
1913 CreateNewResourceType(SecurityDeleteAuthorization);
1915 RTEventClient = CreateNewResourceType(
1916 SecurityDeleteAuthorizationEventClient);
1918 if (!SecurityAuthorizationResType || !RTEventClient)
1919 return;
1921 RTEventClient |= RC_NEVERRETAIN;
1923 if (!AddCallback(&ClientStateCallback, SecurityClientStateCallback, NULL))
1924 return;
1926 extEntry = AddExtension(SECURITY_EXTENSION_NAME,
1927 XSecurityNumberEvents, XSecurityNumberErrors,
1928 ProcSecurityDispatch, SProcSecurityDispatch,
1929 SecurityResetProc, StandardMinorOpcode);
1931 SecurityErrorBase = extEntry->errorBase;
1932 SecurityEventBase = extEntry->eventBase;
1934 EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] =
1935 (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent;
1937 SecurityLoadPropertyAccessList();
1939 } /* SecurityExtensionInit */