1
/* $XdotOrg: xserver/xorg/Xext/security.c,v 1.5 2005/07/03 07:01:04 daniels Exp $ */
2
/* $Xorg: security.c,v 1.4 2001/02/09 02:04:32 xorgcvs Exp $ */
5
Copyright 1996, 1998 The Open Group
7
Permission to use, copy, modify, distribute, and sell this software and its
8
documentation for any purpose is hereby granted without fee, provided that
9
the above copyright notice appear in all copies and that both that
10
copyright notice and this permission notice appear in supporting
13
The above copyright notice and this permission notice shall be included in
14
all copies or substantial portions of the Software.
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
Except as contained in this notice, the name of The Open Group shall not be
24
used in advertising or otherwise to promote the sale, use or other dealings
25
in this Software without prior written authorization from The Open Group.
28
/* $XFree86: xc/programs/Xserver/Xext/security.c,v 1.16tsi Exp $ */
30
#ifdef HAVE_DIX_CONFIG_H
31
#include <dix-config.h>
34
#include "dixstruct.h"
35
#include "extnsionst.h"
36
#include "windowstr.h"
38
#include "scrnintstr.h"
40
#include "colormapst.h"
41
#include "propertyst.h"
42
#define _SECURITY_SERVER
43
#include <X11/extensions/securstr.h>
48
#include <X11/extensions/XLbx.h>
49
extern unsigned char LbxReqCode;
52
#include <X11/extensions/Xagsrv.h>
54
#include <stdio.h> /* for file reading operations */
55
#include <X11/Xatom.h> /* for XA_STRING */
57
#ifndef DEFAULTPOLICYFILE
58
# define DEFAULTPOLICYFILE NULL
60
#if defined(WIN32) || defined(__CYGWIN__)
67
static int SecurityErrorBase; /* first Security error number */
68
static int SecurityEventBase; /* first Security event number */
70
CallbackListPtr SecurityValidateGroupCallback = NULL; /* see security.h */
72
RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */
74
static RESTYPE RTEventClient;
76
/* Proc vectors for untrusted clients, swapped and unswapped versions.
77
* These are the same as the normal proc vectors except that extensions
78
* that haven't declared themselves secure will have ProcBadRequest plugged
79
* in for their major opcode dispatcher. This prevents untrusted clients
80
* from guessing extension major opcodes and using the extension even though
81
* the extension can't be listed or queried.
83
int (*UntrustedProcVector[256])(
86
int (*SwappedUntrustedProcVector[256])(
93
* format is the formatting string to be used to interpret the
94
* remaining arguments.
99
* Writes the message to the log file if security logging is on.
103
SecurityAudit(char *format, ...)
107
if (auditTrailLevel < SECURITY_AUDIT_LEVEL)
109
va_start(args, format);
110
VAuditF(format, args);
112
} /* SecurityAudit */
114
#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
116
/* SecurityDeleteAuthorization
119
* value is the authorization to delete.
120
* id is its resource ID.
125
* Frees everything associated with the authorization.
129
SecurityDeleteAuthorization(
133
SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
134
unsigned short name_len, data_len;
138
OtherClientsPtr pEventClient;
140
/* Remove the auth using the os layer auth manager */
142
status = AuthorizationFromID(pAuth->id, &name_len, &name,
145
status = RemoveAuthorization(name_len, name, data_len, data);
149
/* free the auth timer if there is one */
151
if (pAuth->timer) TimerFree(pAuth->timer);
153
/* send revoke events */
155
while ((pEventClient = pAuth->eventClients))
157
/* send revocation event event */
158
ClientPtr client = rClient(pEventClient);
160
if (!client->clientGone)
162
xSecurityAuthorizationRevokedEvent are;
163
are.type = SecurityEventBase + XSecurityAuthorizationRevoked;
164
are.sequenceNumber = client->sequence;
165
are.authId = pAuth->id;
166
WriteEventsToClient(client, 1, (xEvent *)&are);
168
FreeResource(pEventClient->resource, RT_NONE);
171
/* kill all clients using this auth */
173
for (i = 1; i<currentMaxClients; i++)
175
if (clients[i] && (clients[i]->authId == pAuth->id))
176
CloseDownClient(clients[i]);
179
SecurityAudit("revoked authorization ID %d\n", pAuth->id);
183
} /* SecurityDeleteAuthorization */
186
/* resource delete function for RTEventClient */
188
SecurityDeleteAuthorizationEventClient(
192
OtherClientsPtr pEventClient, prev = NULL;
193
SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
195
for (pEventClient = pAuth->eventClients;
197
pEventClient = pEventClient->next)
199
if (pEventClient->resource == id)
202
prev->next = pEventClient->next;
204
pAuth->eventClients = pEventClient->next;
211
return -1; /* make compiler happy */
212
} /* SecurityDeleteAuthorizationEventClient */
215
/* SecurityComputeAuthorizationTimeout
218
* pAuth is the authorization for which we are computing the timeout
219
* seconds is the number of seconds we want to wait
222
* the number of milliseconds that the auth timer should be set to
225
* Sets pAuth->secondsRemaining to any "overflow" amount of time
226
* that didn't fit in 32 bits worth of milliseconds
230
SecurityComputeAuthorizationTimeout(
231
SecurityAuthorizationPtr pAuth,
232
unsigned int seconds)
234
/* maxSecs is the number of full seconds that can be expressed in
235
* 32 bits worth of milliseconds
237
CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND;
239
if (seconds > maxSecs)
240
{ /* only come here if we want to wait more than 49 days */
241
pAuth->secondsRemaining = seconds - maxSecs;
242
return maxSecs * MILLI_PER_SECOND;
245
{ /* by far the common case */
246
pAuth->secondsRemaining = 0;
247
return seconds * MILLI_PER_SECOND;
249
} /* SecurityStartAuthorizationTimer */
251
/* SecurityAuthorizationExpired
253
* This function is passed as an argument to TimerSet and gets called from
254
* the timer manager in the os layer when its time is up.
257
* timer is the timer for this authorization.
258
* time is the current time.
259
* pval is the authorization whose time is up.
262
* A new time delay in milliseconds if the timer should wait some
266
* Frees the authorization resource if the timeout period is really
267
* over, otherwise recomputes pAuth->secondsRemaining.
271
SecurityAuthorizationExpired(
276
SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval;
278
assert(pAuth->timer == timer);
280
if (pAuth->secondsRemaining)
282
return SecurityComputeAuthorizationTimeout(pAuth,
283
pAuth->secondsRemaining);
287
FreeResource(pAuth->id, RT_NONE);
290
} /* SecurityAuthorizationExpired */
292
/* SecurityStartAuthorizationTimer
295
* pAuth is the authorization whose timer should be started.
300
* A timer is started, set to expire after the timeout period for
301
* this authorization. When it expires, the function
302
* SecurityAuthorizationExpired will be called.
306
SecurityStartAuthorizationTimer(
307
SecurityAuthorizationPtr pAuth)
309
pAuth->timer = TimerSet(pAuth->timer, 0,
310
SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout),
311
SecurityAuthorizationExpired, pAuth);
312
} /* SecurityStartAuthorizationTimer */
315
/* Proc functions all take a client argument, execute the request in
316
* client->requestBuffer, and return a protocol error status.
320
ProcSecurityQueryVersion(
323
/* REQUEST(xSecurityQueryVersionReq); */
324
xSecurityQueryVersionReply rep;
326
/* paranoia: this "can't happen" because this extension is hidden
327
* from untrusted clients, but just in case...
329
if (client->trustLevel != XSecurityClientTrusted)
332
REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
334
rep.sequenceNumber = client->sequence;
336
rep.majorVersion = SECURITY_MAJOR_VERSION;
337
rep.minorVersion = SECURITY_MINOR_VERSION;
341
swaps(&rep.sequenceNumber, n);
342
swaps(&rep.majorVersion, n);
343
swaps(&rep.minorVersion, n);
345
(void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply),
347
return (client->noClientException);
348
} /* ProcSecurityQueryVersion */
352
SecurityEventSelectForAuthorization(
353
SecurityAuthorizationPtr pAuth,
357
OtherClients *pEventClient;
359
for (pEventClient = pAuth->eventClients;
361
pEventClient = pEventClient->next)
363
if (SameClient(pEventClient, client))
366
FreeResource(pEventClient->resource, RT_NONE);
368
pEventClient->mask = mask;
373
pEventClient = (OtherClients *) xalloc(sizeof(OtherClients));
376
pEventClient->mask = mask;
377
pEventClient->resource = FakeClientID(client->index);
378
pEventClient->next = pAuth->eventClients;
379
if (!AddResource(pEventClient->resource, RTEventClient,
385
pAuth->eventClients = pEventClient;
388
} /* SecurityEventSelectForAuthorization */
392
ProcSecurityGenerateAuthorization(
395
REQUEST(xSecurityGenerateAuthorizationReq);
396
int len; /* request length in CARD32s*/
397
Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */
398
SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */
399
int err; /* error to return from this function */
400
XID authId; /* authorization ID assigned by os layer */
401
xSecurityGenerateAuthorizationReply rep; /* reply struct */
402
unsigned int trustLevel; /* trust level of new auth */
403
XID group; /* group of new auth */
404
CARD32 timeout; /* timeout of new auth */
405
CARD32 *values; /* list of supplied attributes */
406
char *protoname; /* auth proto name sent in request */
407
char *protodata; /* auth proto data sent in request */
408
unsigned int authdata_len; /* # bytes of generated auth data */
409
char *pAuthdata; /* generated auth data */
410
Mask eventMask; /* what events on this auth does client want */
412
/* paranoia: this "can't happen" because this extension is hidden
413
* from untrusted clients, but just in case...
415
if (client->trustLevel != XSecurityClientTrusted)
418
/* check request length */
420
REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
421
len = SIZEOF(xSecurityGenerateAuthorizationReq) >> 2;
422
len += (stuff->nbytesAuthProto + (unsigned)3) >> 2;
423
len += (stuff->nbytesAuthData + (unsigned)3) >> 2;
424
values = ((CARD32 *)stuff) + len;
425
len += Ones(stuff->valueMask);
426
if (client->req_len != len)
429
/* check valuemask */
430
if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes)
432
client->errorValue = stuff->valueMask;
438
if (stuff->valueMask & XSecurityTimeout)
443
/* check trustLevel */
444
trustLevel = XSecurityClientUntrusted;
445
if (stuff->valueMask & XSecurityTrustLevel)
447
trustLevel = *values++;
448
if (trustLevel != XSecurityClientTrusted &&
449
trustLevel != XSecurityClientUntrusted)
451
client->errorValue = trustLevel;
458
if (stuff->valueMask & XSecurityGroup)
461
if (SecurityValidateGroupCallback)
463
SecurityValidateGroupInfoRec vgi;
466
CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi);
468
/* if nobody said they recognized it, it's an error */
472
client->errorValue = group;
478
/* check event mask */
480
if (stuff->valueMask & XSecurityEventMask)
482
eventMask = *values++;
483
if (eventMask & ~XSecurityAllEventMasks)
485
client->errorValue = eventMask;
490
protoname = (char *)&stuff[1];
491
protodata = protoname + ((stuff->nbytesAuthProto + (unsigned)3) >> 2);
493
/* call os layer to generate the authorization */
495
authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname,
496
stuff->nbytesAuthData, protodata,
497
&authdata_len, &pAuthdata);
498
if ((XID) ~0L == authId)
500
err = SecurityErrorBase + XSecurityBadAuthorizationProtocol;
504
/* now that we've added the auth, remember to remove it if we have to
505
* abort the request for some reason (like allocation failure)
509
/* associate additional information with this auth ID */
511
pAuth = (SecurityAuthorizationPtr)xalloc(sizeof(SecurityAuthorizationRec));
518
/* fill in the auth fields */
521
pAuth->timeout = timeout;
522
pAuth->group = group;
523
pAuth->trustLevel = trustLevel;
524
pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */
525
pAuth->secondsRemaining = 0;
527
pAuth->eventClients = NULL;
529
/* handle event selection */
532
err = SecurityEventSelectForAuthorization(pAuth, client, eventMask);
537
if (!AddResource(authId, SecurityAuthorizationResType, pAuth))
543
/* start the timer ticking */
545
if (pAuth->timeout != 0)
546
SecurityStartAuthorizationTimer(pAuth);
548
/* tell client the auth id and data */
551
rep.length = (authdata_len + 3) >> 2;
552
rep.sequenceNumber = client->sequence;
554
rep.dataLength = authdata_len;
559
swapl(&rep.length, n);
560
swaps(&rep.sequenceNumber, n);
561
swapl(&rep.authId, n);
562
swaps(&rep.dataLength, n);
565
WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply),
567
WriteToClient(client, authdata_len, pAuthdata);
569
SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n",
570
client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout,
571
pAuth->group, eventMask);
573
/* the request succeeded; don't call RemoveAuthorization or free pAuth */
577
err = client->noClientException;
581
RemoveAuthorization(stuff->nbytesAuthProto, protoname,
582
authdata_len, pAuthdata);
583
if (pAuth) xfree(pAuth);
586
} /* ProcSecurityGenerateAuthorization */
589
ProcSecurityRevokeAuthorization(
592
REQUEST(xSecurityRevokeAuthorizationReq);
593
SecurityAuthorizationPtr pAuth;
595
/* paranoia: this "can't happen" because this extension is hidden
596
* from untrusted clients, but just in case...
598
if (client->trustLevel != XSecurityClientTrusted)
601
REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
603
pAuth = (SecurityAuthorizationPtr)SecurityLookupIDByType(client,
604
stuff->authId, SecurityAuthorizationResType, SecurityDestroyAccess);
606
return SecurityErrorBase + XSecurityBadAuthorization;
608
FreeResource(stuff->authId, RT_NONE);
610
} /* ProcSecurityRevokeAuthorization */
614
ProcSecurityDispatch(
621
case X_SecurityQueryVersion:
622
return ProcSecurityQueryVersion(client);
623
case X_SecurityGenerateAuthorization:
624
return ProcSecurityGenerateAuthorization(client);
625
case X_SecurityRevokeAuthorization:
626
return ProcSecurityRevokeAuthorization(client);
630
} /* ProcSecurityDispatch */
633
SProcSecurityQueryVersion(
636
REQUEST(xSecurityQueryVersionReq);
639
swaps(&stuff->length, n);
640
REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
641
swaps(&stuff->majorVersion, n);
642
swaps(&stuff->minorVersion,n);
643
return ProcSecurityQueryVersion(client);
644
} /* SProcSecurityQueryVersion */
648
SProcSecurityGenerateAuthorization(
651
REQUEST(xSecurityGenerateAuthorizationReq);
654
unsigned long nvalues;
656
swaps(&stuff->length, n);
657
REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
658
swaps(&stuff->nbytesAuthProto, n);
659
swaps(&stuff->nbytesAuthData, n);
660
swapl(&stuff->valueMask, n);
661
values = (CARD32 *)(&stuff[1]) +
662
((stuff->nbytesAuthProto + (unsigned)3) >> 2) +
663
((stuff->nbytesAuthData + (unsigned)3) >> 2);
664
nvalues = (((CARD32 *)stuff) + stuff->length) - values;
665
SwapLongs(values, nvalues);
666
return ProcSecurityGenerateAuthorization(client);
667
} /* SProcSecurityGenerateAuthorization */
671
SProcSecurityRevokeAuthorization(
674
REQUEST(xSecurityRevokeAuthorizationReq);
677
swaps(&stuff->length, n);
678
REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
679
swapl(&stuff->authId, n);
680
return ProcSecurityRevokeAuthorization(client);
681
} /* SProcSecurityRevokeAuthorization */
685
SProcSecurityDispatch(
692
case X_SecurityQueryVersion:
693
return SProcSecurityQueryVersion(client);
694
case X_SecurityGenerateAuthorization:
695
return SProcSecurityGenerateAuthorization(client);
696
case X_SecurityRevokeAuthorization:
697
return SProcSecurityRevokeAuthorization(client);
701
} /* SProcSecurityDispatch */
704
SwapSecurityAuthorizationRevokedEvent(
705
xSecurityAuthorizationRevokedEvent *from,
706
xSecurityAuthorizationRevokedEvent *to)
708
to->type = from->type;
709
to->detail = from->detail;
710
cpswaps(from->sequenceNumber, to->sequenceNumber);
711
cpswapl(from->authId, to->authId);
714
/* SecurityDetermineEventPropogationLimits
716
* This is a helper function for SecurityCheckDeviceAccess.
719
* dev is the device for which the starting and stopping windows for
720
* event propogation should be determined.
721
* The values pointed to by ppWin and ppStopWin are not used.
724
* ppWin is filled in with a pointer to the window at which event
725
* propogation for the given device should start given the current
726
* state of the server (pointer position, window layout, etc.)
727
* ppStopWin is filled in with the window at which event propogation
728
* should stop; events should not go to ppStopWin.
730
* Side Effects: none.
734
SecurityDetermineEventPropogationLimits(
737
WindowPtr *ppStopWin)
739
WindowPtr pFocusWin = dev->focus ? dev->focus->win : NoneWin;
741
if (pFocusWin == NoneWin)
742
{ /* no focus -- events don't go anywhere */
743
*ppWin = *ppStopWin = NULL;
747
if (pFocusWin == PointerRootWin)
748
{ /* focus follows the pointer */
749
*ppWin = GetSpriteWindow();
750
*ppStopWin = NULL; /* propogate all the way to the root */
753
{ /* a real window is set for the focus */
754
WindowPtr pSpriteWin = GetSpriteWindow();
755
*ppStopWin = pFocusWin->parent; /* don't go past the focus window */
757
/* if the pointer is in a subwindow of the focus window, start
758
* at that subwindow, else start at the focus window itself
760
if (IsParent(pFocusWin, pSpriteWin))
762
else *ppWin = pFocusWin;
764
} /* SecurityDetermineEventPropogationLimits */
767
/* SecurityCheckDeviceAccess
770
* client is the client attempting to access a device.
771
* dev is the device being accessed.
772
* fromRequest is TRUE if the device access is a direct result of
773
* the client executing some request and FALSE if it is a
774
* result of the server trying to send an event (e.g. KeymapNotify)
777
* TRUE if the device access should be allowed, else FALSE.
780
* An audit message is generated if access is denied.
784
SecurityCheckDeviceAccess(client, dev, fromRequest)
789
WindowPtr pWin, pStopWin;
790
Bool untrusted_got_event;
791
Bool found_event_window;
795
/* trusted clients always allowed to do anything */
796
if (client->trustLevel == XSecurityClientTrusted)
799
/* device security other than keyboard is not implemented yet */
800
if (dev != inputInfo.keyboard)
803
/* some untrusted client wants access */
807
reqtype = ((xReq *)client->requestBuffer)->reqType;
810
/* never allow these */
811
case X_ChangeKeyboardMapping:
812
case X_ChangeKeyboardControl:
813
case X_SetModifierMapping:
814
SecurityAudit("client %d attempted request %d\n",
815
client->index, reqtype);
822
untrusted_got_event = FALSE;
823
found_event_window = FALSE;
827
untrusted_got_event =
828
((rClient(dev->grab))->trustLevel != XSecurityClientTrusted);
832
SecurityDetermineEventPropogationLimits(dev, &pWin, &pStopWin);
834
eventmask = KeyPressMask | KeyReleaseMask;
835
while ( (pWin != pStopWin) && !found_event_window)
839
if (pWin->eventMask & eventmask)
841
found_event_window = TRUE;
842
client = wClient(pWin);
843
if (client->trustLevel != 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 (client->trustLevel != XSecurityClientTrusted)
858
untrusted_got_event = TRUE;
864
if (wDontPropagateMask(pWin) & eventmask)
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";
879
SecurityAudit("client %d attempted request %d device %d (%s)\n",
880
client->index, reqtype, dev->id, devname);
882
SecurityAudit("client %d attempted to access device %d (%s)\n",
883
client->index, dev->id, devname);
885
return untrusted_got_event;
886
} /* SecurityCheckDeviceAccess */
890
/* SecurityAuditResourceIDAccess
893
* client is the client doing the resource access.
894
* id is the resource id.
899
* An audit message is generated with details of the denied
904
SecurityAuditResourceIDAccess(
908
int cid = CLIENT_ID(id);
909
int reqtype = ((xReq *)client->requestBuffer)->reqType;
912
case X_ChangeProperty:
913
case X_DeleteProperty:
916
xChangePropertyReq *req =
917
(xChangePropertyReq *)client->requestBuffer;
918
int propertyatom = req->property;
919
char *propertyname = NameForAtom(propertyatom);
921
SecurityAudit("client %d attempted request %d with window 0x%x property %s of client %d\n",
922
client->index, reqtype, id, propertyname, cid);
927
SecurityAudit("client %d attempted request %d with resource 0x%x of client %d\n",
928
client->index, reqtype, id, cid);
933
} /* SecurityAuditResourceIDAccess */
936
/* SecurityCheckResourceIDAccess
938
* This function gets plugged into client->CheckAccess and is called from
939
* SecurityLookupIDByType/Class to determine if the client can access the
943
* client is the client doing the resource access.
944
* id is the resource id.
945
* rtype is its type or class.
946
* access_mode represents the intended use of the resource; see
948
* rval is a pointer to the resource structure for this resource.
951
* If access is granted, the value of rval that was passed in, else NULL.
954
* Disallowed resource accesses are audited.
958
SecurityCheckResourceIDAccess(
965
int cid = CLIENT_ID(id);
966
int reqtype = ((xReq *)client->requestBuffer)->reqType;
968
if (SecurityUnknownAccess == access_mode)
969
return rval; /* for compatibility, we have to allow access */
972
{ /* these are always allowed */
974
case X_TranslateCoords:
976
/* property access is controlled in SecurityCheckPropertyAccess */
978
case X_ChangeProperty:
979
case X_DeleteProperty:
980
case X_RotateProperties:
981
case X_ListProperties:
988
{ /* not a server-owned resource */
990
* The following 'if' restricts clients to only access resources at
991
* the same trustLevel. Since there are currently only two trust levels,
992
* and trusted clients never call this function, this degenerates into
993
* saying that untrusted clients can only access resources of other
994
* untrusted clients. One way to add the notion of groups would be to
995
* allow values other than Trusted (0) and Untrusted (1) for this field.
996
* Clients at the same trust level would be able to use each other's
997
* resources, but not those of clients at other trust levels. I haven't
998
* tried it, but this probably mostly works already. The obvious
999
* competing alternative for grouping clients for security purposes is to
1000
* use app groups. dpw
1002
if (client->trustLevel == clients[cid]->trustLevel
1004
|| (RT_COLORMAP == rtype &&
1005
XagDefaultColormap (client) == (Colormap) id)
1010
return SecurityAuditResourceIDAccess(client, id);
1012
else /* server-owned resource - probably a default colormap or root window */
1014
if (RT_WINDOW == rtype || RC_DRAWABLE == rtype)
1017
{ /* the following operations are allowed on root windows */
1018
case X_CreatePixmap:
1020
case X_CreateWindow:
1021
case X_CreateColormap:
1022
case X_ListProperties:
1024
case X_UngrabButton:
1025
case X_QueryBestSize:
1026
case X_GetWindowAttributes:
1029
{ /* see if it is an event specified by the ICCCM */
1030
xSendEventReq *req = (xSendEventReq *)
1031
(client->requestBuffer);
1032
if (req->propagate == xTrue
1034
(req->eventMask != ColormapChangeMask &&
1035
req->eventMask != StructureNotifyMask &&
1037
(SubstructureRedirectMask|SubstructureNotifyMask)
1040
(req->event.u.u.type != UnmapNotify &&
1041
req->event.u.u.type != ConfigureRequest &&
1042
req->event.u.u.type != ClientMessage
1045
{ /* not an ICCCM event */
1046
return SecurityAuditResourceIDAccess(client, id);
1049
} /* case X_SendEvent on root */
1051
case X_ChangeWindowAttributes:
1052
{ /* Allow selection of PropertyNotify and StructureNotify
1053
* events on the root.
1055
xChangeWindowAttributesReq *req =
1056
(xChangeWindowAttributesReq *)(client->requestBuffer);
1057
if (req->valueMask == CWEventMask)
1059
CARD32 value = *((CARD32 *)(req + 1));
1061
~(PropertyChangeMask|StructureNotifyMask)) == 0)
1064
return SecurityAuditResourceIDAccess(client, id);
1065
} /* case X_ChangeWindowAttributes on root */
1070
/* XXX really need per extension dispatching */
1071
if (reqtype == LbxReqCode) {
1072
switch (((xReq *)client->requestBuffer)->data) {
1073
case X_LbxGetProperty:
1074
case X_LbxChangeProperty:
1081
/* others not allowed */
1082
return SecurityAuditResourceIDAccess(client, id);
1085
} /* end server-owned window or drawable */
1086
else if (SecurityAuthorizationResType == rtype)
1088
SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)rval;
1089
if (pAuth->trustLevel != client->trustLevel)
1090
return SecurityAuditResourceIDAccess(client, id);
1092
else if (RT_COLORMAP != rtype)
1093
{ /* don't allow anything else besides colormaps */
1094
return SecurityAuditResourceIDAccess(client, id);
1098
} /* SecurityCheckResourceIDAccess */
1101
/* SecurityClientStateCallback
1104
* pcbl is &ClientStateCallback.
1106
* calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
1107
* which contains information about client state changes.
1113
* If a new client is connecting, its authorization ID is copied to
1114
* client->authID. If this is a generated authorization, its reference
1115
* count is bumped, its timer is cancelled if it was running, and its
1116
* trustlevel is copied to client->trustLevel.
1118
* If a client is disconnecting and the client was using a generated
1119
* authorization, the authorization's reference count is decremented, and
1120
* if it is now zero, the timer for this authorization is started.
1124
SecurityClientStateCallback(
1125
CallbackListPtr *pcbl,
1129
NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
1130
ClientPtr client = pci->client;
1132
switch (client->clientState)
1134
case ClientStateRunning:
1136
XID authId = AuthorizationIDOfClient(client);
1137
SecurityAuthorizationPtr pAuth;
1139
client->authId = authId;
1140
pAuth = (SecurityAuthorizationPtr)LookupIDByType(authId,
1141
SecurityAuthorizationResType);
1143
{ /* it is a generated authorization */
1145
if (pAuth->refcnt == 1)
1147
if (pAuth->timer) TimerCancel(pAuth->timer);
1149
client->trustLevel = pAuth->trustLevel;
1150
if (client->trustLevel != XSecurityClientTrusted)
1152
client->CheckAccess = SecurityCheckResourceIDAccess;
1153
client->requestVector = client->swapped ?
1154
SwappedUntrustedProcVector : UntrustedProcVector;
1159
case ClientStateGone:
1160
case ClientStateRetained: /* client disconnected */
1162
XID authId = client->authId;
1163
SecurityAuthorizationPtr pAuth;
1165
pAuth = (SecurityAuthorizationPtr)LookupIDByType(authId,
1166
SecurityAuthorizationResType);
1168
{ /* it is a generated authorization */
1170
if (pAuth->refcnt == 0)
1172
SecurityStartAuthorizationTimer(pAuth);
1179
} /* SecurityClientStateCallback */
1183
SecuritySameLevel(client, authId)
1187
SecurityAuthorizationPtr pAuth;
1189
pAuth = (SecurityAuthorizationPtr)LookupIDByType(authId,
1190
SecurityAuthorizationResType);
1192
return client->trustLevel == pAuth->trustLevel;
1193
return client->trustLevel == XSecurityClientTrusted;
1197
/* SecurityCensorImage
1199
* Called after pScreen->GetImage to prevent pieces or trusted windows from
1200
* being returned in image data from an untrusted window.
1203
* client is the client doing the GetImage.
1204
* pVisibleRegion is the visible region of the window.
1205
* widthBytesLine is the width in bytes of one horizontal line in pBuf.
1206
* pDraw is the source window.
1207
* x, y, w, h is the rectangle of image data from pDraw in pBuf.
1208
* format is the format of the image data in pBuf: ZPixmap or XYPixmap.
1209
* pBuf is the image data.
1214
* Any part of the rectangle (x, y, w, h) that is outside the visible
1215
* region of the window will be destroyed (overwritten) in pBuf.
1218
SecurityCensorImage(client, pVisibleRegion, widthBytesLine, pDraw, x, y, w, h,
1221
RegionPtr pVisibleRegion;
1222
long widthBytesLine;
1225
unsigned int format;
1228
ScreenPtr pScreen = pDraw->pScreen;
1229
RegionRec imageRegion; /* region representing x,y,w,h */
1230
RegionRec censorRegion; /* region to obliterate */
1236
imageBox.x2 = x + w;
1237
imageBox.y2 = y + h;
1238
REGION_INIT(pScreen, &imageRegion, &imageBox, 1);
1239
REGION_NULL(pScreen, &censorRegion);
1241
/* censorRegion = imageRegion - visibleRegion */
1242
REGION_SUBTRACT(pScreen, &censorRegion, &imageRegion, pVisibleRegion);
1243
nRects = REGION_NUM_RECTS(&censorRegion);
1245
{ /* we have something to censor */
1246
GCPtr pScratchGC = NULL;
1247
PixmapPtr pPix = NULL;
1248
xRectangle *pRects = NULL;
1249
Bool failed = FALSE;
1251
int bitsPerPixel = 1;
1255
/* convert region to list-of-rectangles for PolyFillRect */
1257
pRects = (xRectangle *)ALLOCATE_LOCAL(nRects * sizeof(xRectangle *));
1263
for (pBox = REGION_RECTS(&censorRegion), i = 0;
1267
pRects[i].x = pBox->x1;
1268
pRects[i].y = pBox->y1 - imageBox.y1;
1269
pRects[i].width = pBox->x2 - pBox->x1;
1270
pRects[i].height = pBox->y2 - pBox->y1;
1273
/* use pBuf as a fake pixmap */
1275
if (format == ZPixmap)
1277
depth = pDraw->depth;
1278
bitsPerPixel = pDraw->bitsPerPixel;
1281
pPix = GetScratchPixmapHeader(pDraw->pScreen, w, h,
1282
depth, bitsPerPixel,
1283
widthBytesLine, (pointer)pBuf);
1290
pScratchGC = GetScratchGC(depth, pPix->drawable.pScreen);
1297
ValidateGC(&pPix->drawable, pScratchGC);
1298
(* pScratchGC->ops->PolyFillRect)(&pPix->drawable,
1299
pScratchGC, nRects, pRects);
1304
/* Censoring was not completed above. To be safe, wipe out
1305
* all the image data so that nothing trusted gets out.
1307
bzero(pBuf, (int)(widthBytesLine * h));
1309
if (pRects) DEALLOCATE_LOCAL(pRects);
1310
if (pScratchGC) FreeScratchGC(pScratchGC);
1311
if (pPix) FreeScratchPixmapHeader(pPix);
1313
REGION_UNINIT(pScreen, &imageRegion);
1314
REGION_UNINIT(pScreen, &censorRegion);
1315
} /* SecurityCensorImage */
1317
/**********************************************************************/
1319
typedef struct _PropertyAccessRec {
1321
ATOM mustHaveProperty;
1322
char *mustHaveValue;
1323
char windowRestriction;
1324
#define SecurityAnyWindow 0
1325
#define SecurityRootWindow 1
1326
#define SecurityWindowWithProperty 2
1330
struct _PropertyAccessRec *next;
1331
} PropertyAccessRec, *PropertyAccessPtr;
1333
static PropertyAccessPtr PropertyAccessList = NULL;
1334
static char SecurityDefaultAction = SecurityErrorOperation;
1335
static char *SecurityPolicyFile = DEFAULTPOLICYFILE;
1336
static ATOM SecurityMaxPropertyName = 0;
1338
static char *SecurityKeywords[] = {
1339
#define SecurityKeywordComment 0
1341
#define SecurityKeywordProperty 1
1343
#define SecurityKeywordSitePolicy 2
1345
#define SecurityKeywordRoot 3
1347
#define SecurityKeywordAny 4
1351
#define NUMKEYWORDS (sizeof(SecurityKeywords) / sizeof(char *))
1354
/*#define PROPDEBUG 1*/
1357
SecurityFreePropertyAccessList(void)
1359
while (PropertyAccessList)
1361
PropertyAccessPtr freeit = PropertyAccessList;
1362
PropertyAccessList = PropertyAccessList->next;
1365
} /* SecurityFreePropertyAccessList */
1368
#define SecurityIsWhitespace(c) ( (c == ' ') || (c == '\t') || (c == '\n') )
1370
#define SecurityIsWhitespace(c) ( (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') )
1374
SecuritySkipWhitespace(
1377
while (SecurityIsWhitespace(*p))
1380
} /* SecuritySkipWhitespace */
1384
SecurityParseString(
1387
char *startOfString;
1391
s = SecuritySkipWhitespace(s);
1393
if (*s == '"' || *s == '\'')
1397
while (*s && (*s != endChar))
1403
while (*s && !SecurityIsWhitespace(*s))
1410
return startOfString;
1415
return (endChar) ? NULL : startOfString;
1417
} /* SecurityParseString */
1421
SecurityParseKeyword(
1426
s = SecuritySkipWhitespace(s);
1427
for (i = 0; i < NUMKEYWORDS; i++)
1429
int len = strlen(SecurityKeywords[i]);
1430
if (strncmp(s, SecurityKeywords[i], len) == 0)
1438
} /* SecurityParseKeyword */
1442
SecurityParsePropertyAccessRule(
1447
char action = SecurityDefaultAction;
1448
char readAction, writeAction, destroyAction;
1449
PropertyAccessPtr pacl, prev, cur;
1450
char *mustHaveProperty = NULL;
1451
char *mustHaveValue = NULL;
1453
char windowRestriction;
1457
/* get property name */
1458
propname = SecurityParseString(&p);
1459
if (!propname || (strlen(propname) == 0))
1462
/* get window on which property must reside for rule to apply */
1464
keyword = SecurityParseKeyword(&p);
1465
if (keyword == SecurityKeywordRoot)
1466
windowRestriction = SecurityRootWindow;
1467
else if (keyword == SecurityKeywordAny)
1468
windowRestriction = SecurityAnyWindow;
1469
else /* not root or any, must be a property name */
1471
mustHaveProperty = SecurityParseString(&p);
1472
if (!mustHaveProperty || (strlen(mustHaveProperty) == 0))
1474
windowRestriction = SecurityWindowWithProperty;
1475
p = SecuritySkipWhitespace(p);
1477
{ /* property value is specified too */
1478
p++; /* skip over '=' */
1479
mustHaveValue = SecurityParseString(&p);
1485
/* get operations and actions */
1488
readAction = writeAction = destroyAction = SecurityDefaultAction;
1489
while ( (c = *p++) && !invalid)
1493
case 'i': action = SecurityIgnoreOperation; break;
1494
case 'a': action = SecurityAllowOperation; break;
1495
case 'e': action = SecurityErrorOperation; break;
1497
case 'r': readAction = action; break;
1498
case 'w': writeAction = action; break;
1499
case 'd': destroyAction = action; break;
1502
if (!SecurityIsWhitespace(c))
1510
/* We've successfully collected all the information needed for this
1511
* property access rule. Now record it in a PropertyAccessRec.
1513
size = sizeof(PropertyAccessRec);
1515
/* If there is a property value string, allocate space for it
1516
* right after the PropertyAccessRec.
1519
size += strlen(mustHaveValue) + 1;
1520
pacl = (PropertyAccessPtr)Xalloc(size);
1524
pacl->name = MakeAtom(propname, strlen(propname), TRUE);
1525
if (pacl->name == BAD_RESOURCE)
1530
if (mustHaveProperty)
1532
pacl->mustHaveProperty = MakeAtom(mustHaveProperty,
1533
strlen(mustHaveProperty), TRUE);
1534
if (pacl->mustHaveProperty == BAD_RESOURCE)
1541
pacl->mustHaveProperty = 0;
1545
pacl->mustHaveValue = (char *)(pacl + 1);
1546
strcpy(pacl->mustHaveValue, mustHaveValue);
1549
pacl->mustHaveValue = NULL;
1551
SecurityMaxPropertyName = max(SecurityMaxPropertyName, pacl->name);
1553
pacl->windowRestriction = windowRestriction;
1554
pacl->readAction = readAction;
1555
pacl->writeAction = writeAction;
1556
pacl->destroyAction = destroyAction;
1558
/* link the new rule into the list of rules in order of increasing
1559
* property name (atom) value to make searching easier
1562
for (prev = NULL, cur = PropertyAccessList;
1563
cur && cur->name <= pacl->name;
1564
prev = cur, cur = cur->next)
1569
PropertyAccessList = pacl;
1577
} /* SecurityParsePropertyAccessRule */
1579
static char **SecurityPolicyStrings = NULL;
1580
static int nSecurityPolicyStrings = 0;
1583
SecurityParseSitePolicy(
1586
char *policyStr = SecurityParseString(&p);
1587
char *copyPolicyStr;
1593
copyPolicyStr = (char *)Xalloc(strlen(policyStr) + 1);
1596
strcpy(copyPolicyStr, policyStr);
1597
newStrings = (char **)Xrealloc(SecurityPolicyStrings,
1598
sizeof (char *) * (nSecurityPolicyStrings + 1));
1601
Xfree(copyPolicyStr);
1605
SecurityPolicyStrings = newStrings;
1606
SecurityPolicyStrings[nSecurityPolicyStrings++] = copyPolicyStr;
1610
} /* SecurityParseSitePolicy */
1614
SecurityGetSitePolicyStrings(n)
1617
*n = nSecurityPolicyStrings;
1618
return SecurityPolicyStrings;
1619
} /* SecurityGetSitePolicyStrings */
1622
SecurityFreeSitePolicyStrings(void)
1624
if (SecurityPolicyStrings)
1626
assert(nSecurityPolicyStrings);
1627
while (nSecurityPolicyStrings--)
1629
Xfree(SecurityPolicyStrings[nSecurityPolicyStrings]);
1631
Xfree(SecurityPolicyStrings);
1632
SecurityPolicyStrings = NULL;
1633
nSecurityPolicyStrings = 0;
1635
} /* SecurityFreeSitePolicyStrings */
1639
SecurityLoadPropertyAccessList(void)
1644
SecurityMaxPropertyName = 0;
1646
if (!SecurityPolicyFile)
1650
f = fopen(SecurityPolicyFile, "r");
1652
f = fopen((char*)__XOS2RedirRoot(SecurityPolicyFile), "r");
1656
ErrorF("error opening security policy file %s\n",
1657
SecurityPolicyFile);
1667
if (!(p = fgets(buf, sizeof(buf), f)))
1671
/* if first line, check version number */
1672
if (lineNumber == 1)
1674
char *v = SecurityParseString(&p);
1675
if (strcmp(v, SECURITY_POLICY_FILE_VERSION) != 0)
1677
ErrorF("%s: invalid security policy file version, ignoring file\n",
1678
SecurityPolicyFile);
1685
switch (SecurityParseKeyword(&p))
1687
case SecurityKeywordComment:
1691
case SecurityKeywordProperty:
1692
validLine = SecurityParsePropertyAccessRule(p);
1695
case SecurityKeywordSitePolicy:
1696
validLine = SecurityParseSitePolicy(p);
1700
validLine = (*p == '\0'); /* blank lines OK, others not */
1706
ErrorF("Line %d of %s invalid, ignoring\n",
1707
lineNumber, SecurityPolicyFile);
1708
} /* end while more input */
1712
PropertyAccessPtr pacl;
1714
for (pacl = PropertyAccessList; pacl; pacl = pacl->next)
1716
ErrorF("property %s ", NameForAtom(pacl->name));
1717
switch (pacl->windowRestriction)
1719
case SecurityAnyWindow: ErrorF("any "); break;
1720
case SecurityRootWindow: ErrorF("root "); break;
1721
case SecurityWindowWithProperty:
1723
ErrorF("%s ", NameForAtom(pacl->mustHaveProperty));
1724
if (pacl->mustHaveValue)
1725
ErrorF(" = \"%s\" ", pacl->mustHaveValue);
1730
ErrorF("%cr %cw %cd\n", op[pacl->readAction],
1731
op[pacl->writeAction], op[pacl->destroyAction]);
1734
#endif /* PROPDEBUG */
1737
} /* SecurityLoadPropertyAccessList */
1741
SecurityMatchString(
1751
while (!(match = SecurityMatchString(ws, cs)) && *cs)
1757
else if (*ws == *cs)
1764
return ( ( (*ws == '\0') || ((*ws == '*') && *(ws+1) == '\0') )
1766
} /* SecurityMatchString */
1769
#include <sys/types.h>
1770
#include <sys/stat.h>
1775
SecurityCheckPropertyAccess(client, pWin, propertyName, access_mode)
1781
PropertyAccessPtr pacl;
1782
char action = SecurityDefaultAction;
1784
/* if client trusted or window untrusted, allow operation */
1786
if ( (client->trustLevel == XSecurityClientTrusted) ||
1787
(wClient(pWin)->trustLevel != XSecurityClientTrusted) )
1788
return SecurityAllowOperation;
1791
/* For testing, it's more convenient if the property rules file gets
1792
* reloaded whenever it changes, so we can rapidly try things without
1793
* having to reset the server.
1797
static time_t lastmod = 0;
1798
int ret = stat(SecurityPolicyFile , &buf);
1799
if ( (ret == 0) && (buf.st_mtime > lastmod) )
1801
ErrorF("reloading property rules\n");
1802
SecurityFreePropertyAccessList();
1803
SecurityLoadPropertyAccessList();
1804
lastmod = buf.st_mtime;
1809
/* If the property atom is bigger than any atoms on the list,
1810
* we know we won't find it, so don't even bother looking.
1812
if (propertyName <= SecurityMaxPropertyName)
1814
/* untrusted client operating on trusted window; see if it's allowed */
1816
for (pacl = PropertyAccessList; pacl; pacl = pacl->next)
1818
if (pacl->name < propertyName)
1820
if (pacl->name > propertyName)
1823
/* pacl->name == propertyName, so see if it applies to this window */
1825
switch (pacl->windowRestriction)
1827
case SecurityAnyWindow: /* always applies */
1830
case SecurityRootWindow:
1832
/* if not a root window, this rule doesn't apply */
1838
case SecurityWindowWithProperty:
1840
PropertyPtr pProp = wUserProps (pWin);
1847
if (pProp->propertyName == pacl->mustHaveProperty)
1849
pProp = pProp->next;
1853
if (!pacl->mustHaveValue)
1855
if (pProp->type != XA_STRING || pProp->format != 8)
1859
pEndData = ((char *)pProp->data) + pProp->size;
1860
while (!match && p < pEndData)
1862
if (SecurityMatchString(pacl->mustHaveValue, p))
1865
{ /* skip to the next string */
1866
while (*p++ && p < pEndData)
1873
break; /* end case SecurityWindowWithProperty */
1874
} /* end switch on windowRestriction */
1876
/* If we get here, the property access rule pacl applies.
1877
* If pacl doesn't apply, something above should have
1878
* executed a continue, which will skip the follwing code.
1880
action = SecurityAllowOperation;
1881
if (access_mode & SecurityReadAccess)
1882
action = max(action, pacl->readAction);
1883
if (access_mode & SecurityWriteAccess)
1884
action = max(action, pacl->writeAction);
1885
if (access_mode & SecurityDestroyAccess)
1886
action = max(action, pacl->destroyAction);
1888
} /* end for each pacl */
1889
} /* end if propertyName <= SecurityMaxPropertyName */
1891
if (SecurityAllowOperation != action)
1892
{ /* audit the access violation */
1893
int cid = CLIENT_ID(pWin->drawable.id);
1894
int reqtype = ((xReq *)client->requestBuffer)->reqType;
1895
char *actionstr = (SecurityIgnoreOperation == action) ?
1896
"ignored" : "error";
1897
SecurityAudit("client %d attempted request %d with window 0x%x property %s (atom 0x%x) of client %d, %s\n",
1898
client->index, reqtype, pWin->drawable.id,
1899
NameForAtom(propertyName), propertyName, cid, actionstr);
1902
} /* SecurityCheckPropertyAccess */
1905
/* SecurityResetProc
1908
* extEntry is the extension information for the security extension.
1913
* Performs any cleanup needed by Security at server shutdown time.
1918
ExtensionEntry *extEntry)
1920
SecurityFreePropertyAccessList();
1921
SecurityFreeSitePolicyStrings();
1922
} /* SecurityResetProc */
1926
XSecurityOptions(argc, argv, i)
1931
if (strcmp(argv[i], "-sp") == 0)
1934
SecurityPolicyFile = argv[++i];
1938
} /* XSecurityOptions */
1942
/* SecurityExtensionInit
1949
* Enables the Security extension if possible.
1953
SecurityExtensionInit(INITARGS)
1955
ExtensionEntry *extEntry;
1958
SecurityAuthorizationResType =
1959
CreateNewResourceType(SecurityDeleteAuthorization);
1961
RTEventClient = CreateNewResourceType(
1962
SecurityDeleteAuthorizationEventClient);
1964
if (!SecurityAuthorizationResType || !RTEventClient)
1967
RTEventClient |= RC_NEVERRETAIN;
1969
if (!AddCallback(&ClientStateCallback, SecurityClientStateCallback, NULL))
1972
extEntry = AddExtension(SECURITY_EXTENSION_NAME,
1973
XSecurityNumberEvents, XSecurityNumberErrors,
1974
ProcSecurityDispatch, SProcSecurityDispatch,
1975
SecurityResetProc, StandardMinorOpcode);
1977
SecurityErrorBase = extEntry->errorBase;
1978
SecurityEventBase = extEntry->eventBase;
1980
EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] =
1981
(EventSwapPtr)SwapSecurityAuthorizationRevokedEvent;
1983
/* initialize untrusted proc vectors */
1985
for (i = 0; i < 128; i++)
1987
UntrustedProcVector[i] = ProcVector[i];
1988
SwappedUntrustedProcVector[i] = SwappedProcVector[i];
1991
/* make sure insecure extensions are not allowed */
1993
for (i = 128; i < 256; i++)
1995
if (!UntrustedProcVector[i])
1997
UntrustedProcVector[i] = ProcBadRequest;
1998
SwappedUntrustedProcVector[i] = ProcBadRequest;
2002
SecurityLoadPropertyAccessList();
2004
} /* SecurityExtensionInit */