diff options
Diffstat (limited to 'xorg-server/Xext/security.c')
-rw-r--r-- | xorg-server/Xext/security.c | 2287 |
1 files changed, 1141 insertions, 1146 deletions
diff --git a/xorg-server/Xext/security.c b/xorg-server/Xext/security.c index d687926c6..08d8158e3 100644 --- a/xorg-server/Xext/security.c +++ b/xorg-server/Xext/security.c @@ -1,1146 +1,1141 @@ -/*
-
-Copyright 1996, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include "scrnintstr.h"
-#include "inputstr.h"
-#include "windowstr.h"
-#include "propertyst.h"
-#include "colormapst.h"
-#include "privates.h"
-#include "registry.h"
-#include "xacestr.h"
-#include "securitysrv.h"
-#include <X11/extensions/securproto.h>
-#include "modinit.h"
-#include "protocol-versions.h"
-
-/* Extension stuff */
-static int SecurityErrorBase; /* first Security error number */
-static int SecurityEventBase; /* first Security event number */
-
-RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */
-static RESTYPE RTEventClient;
-
-static CallbackListPtr SecurityValidateGroupCallback = NULL;
-
-/* Private state record */
-static DevPrivateKeyRec stateKeyRec;
-#define stateKey (&stateKeyRec)
-
-/* This is what we store as client security state */
-typedef struct {
- int haveState;
- unsigned int trustLevel;
- XID authId;
-} SecurityStateRec;
-
-/* Extensions that untrusted clients shouldn't have access to */
-static char *SecurityTrustedExtensions[] = {
- "XC-MISC",
- "BIG-REQUESTS",
- "XpExtension",
- NULL
-};
-
-/*
- * Access modes that untrusted clients are allowed on trusted objects.
- */
-static const Mask SecurityResourceMask =
- DixGetAttrAccess | DixReceiveAccess | DixListPropAccess |
- DixGetPropAccess | DixListAccess;
-static const Mask SecurityWindowExtraMask = DixRemoveAccess;
-static const Mask SecurityRootWindowExtraMask =
- DixReceiveAccess | DixSendAccess | DixAddAccess | DixRemoveAccess;
-static const Mask SecurityDeviceMask =
- DixGetAttrAccess | DixReceiveAccess | DixGetFocusAccess |
- DixGrabAccess | DixSetAttrAccess | DixUseAccess;
-static const Mask SecurityServerMask = DixGetAttrAccess | DixGrabAccess;
-static const Mask SecurityClientMask = DixGetAttrAccess;
-
-
-/* SecurityAudit
- *
- * Arguments:
- * format is the formatting string to be used to interpret the
- * remaining arguments.
- *
- * Returns: nothing.
- *
- * Side Effects:
- * Writes the message to the log file if security logging is on.
- */
-
-static void
-SecurityAudit(char *format, ...)
-{
- va_list args;
-
- if (auditTrailLevel < SECURITY_AUDIT_LEVEL)
- return;
- va_start(args, format);
- VAuditF(format, args);
- va_end(args);
-} /* SecurityAudit */
-
-/*
- * Performs a Security permission check.
- */
-static int
-SecurityDoCheck(SecurityStateRec *subj, SecurityStateRec *obj,
- Mask requested, Mask allowed)
-{
- if (!subj->haveState || !obj->haveState)
- return Success;
- if (subj->trustLevel == XSecurityClientTrusted)
- return Success;
- if (obj->trustLevel != XSecurityClientTrusted)
- return Success;
- if ((requested | allowed) == allowed)
- return Success;
-
- return BadAccess;
-}
-
-/*
- * Labels initial server objects.
- */
-static void
-SecurityLabelInitial(void)
-{
- SecurityStateRec *state;
-
- /* Do the serverClient */
- state = dixLookupPrivate(&serverClient->devPrivates, stateKey);
- state->trustLevel = XSecurityClientTrusted;
- state->haveState = TRUE;
-}
-
-/*
- * Looks up a request name
- */
-static _X_INLINE const char *
-SecurityLookupRequestName(ClientPtr client)
-{
- int major = ((xReq *)client->requestBuffer)->reqType;
- int minor = MinorOpcodeOfRequest(client);
- return LookupRequestName(major, minor);
-}
-
-
-/* SecurityDeleteAuthorization
- *
- * Arguments:
- * value is the authorization to delete.
- * id is its resource ID.
- *
- * Returns: Success.
- *
- * Side Effects:
- * Frees everything associated with the authorization.
- */
-
-static int
-SecurityDeleteAuthorization(
- pointer value,
- XID id)
-{
- SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
- unsigned short name_len, data_len;
- char *name, *data;
- int status;
- int i;
- OtherClientsPtr pEventClient;
-
- /* Remove the auth using the os layer auth manager */
-
- status = AuthorizationFromID(pAuth->id, &name_len, &name,
- &data_len, &data);
- assert(status);
- status = RemoveAuthorization(name_len, name, data_len, data);
- assert(status);
- (void)status;
-
- /* free the auth timer if there is one */
-
- if (pAuth->timer) TimerFree(pAuth->timer);
-
- /* send revoke events */
-
- while ((pEventClient = pAuth->eventClients))
- {
- /* send revocation event event */
- xSecurityAuthorizationRevokedEvent are;
- are.type = SecurityEventBase + XSecurityAuthorizationRevoked;
- are.authId = pAuth->id;
- WriteEventsToClient(rClient(pEventClient), 1, (xEvent *)&are);
- FreeResource(pEventClient->resource, RT_NONE);
- }
-
- /* kill all clients using this auth */
-
- for (i = 1; i<currentMaxClients; i++)
- if (clients[i]) {
- SecurityStateRec *state;
- state = dixLookupPrivate(&clients[i]->devPrivates, stateKey);
- if (state->haveState && state->authId == pAuth->id)
- CloseDownClient(clients[i]);
- }
-
- SecurityAudit("revoked authorization ID %d\n", pAuth->id);
- free(pAuth);
- return Success;
-
-} /* SecurityDeleteAuthorization */
-
-
-/* resource delete function for RTEventClient */
-static int
-SecurityDeleteAuthorizationEventClient(
- pointer value,
- XID id)
-{
- OtherClientsPtr pEventClient, prev = NULL;
- SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value;
-
- for (pEventClient = pAuth->eventClients;
- pEventClient;
- pEventClient = pEventClient->next)
- {
- if (pEventClient->resource == id)
- {
- if (prev)
- prev->next = pEventClient->next;
- else
- pAuth->eventClients = pEventClient->next;
- free(pEventClient);
- return Success;
- }
- prev = pEventClient;
- }
- /*NOTREACHED*/
- return -1; /* make compiler happy */
-} /* SecurityDeleteAuthorizationEventClient */
-
-
-/* SecurityComputeAuthorizationTimeout
- *
- * Arguments:
- * pAuth is the authorization for which we are computing the timeout
- * seconds is the number of seconds we want to wait
- *
- * Returns:
- * the number of milliseconds that the auth timer should be set to
- *
- * Side Effects:
- * Sets pAuth->secondsRemaining to any "overflow" amount of time
- * that didn't fit in 32 bits worth of milliseconds
- */
-
-static CARD32
-SecurityComputeAuthorizationTimeout(
- SecurityAuthorizationPtr pAuth,
- unsigned int seconds)
-{
- /* maxSecs is the number of full seconds that can be expressed in
- * 32 bits worth of milliseconds
- */
- CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND;
-
- if (seconds > maxSecs)
- { /* only come here if we want to wait more than 49 days */
- pAuth->secondsRemaining = seconds - maxSecs;
- return maxSecs * MILLI_PER_SECOND;
- }
- else
- { /* by far the common case */
- pAuth->secondsRemaining = 0;
- return seconds * MILLI_PER_SECOND;
- }
-} /* SecurityStartAuthorizationTimer */
-
-/* SecurityAuthorizationExpired
- *
- * This function is passed as an argument to TimerSet and gets called from
- * the timer manager in the os layer when its time is up.
- *
- * Arguments:
- * timer is the timer for this authorization.
- * time is the current time.
- * pval is the authorization whose time is up.
- *
- * Returns:
- * A new time delay in milliseconds if the timer should wait some
- * more, else zero.
- *
- * Side Effects:
- * Frees the authorization resource if the timeout period is really
- * over, otherwise recomputes pAuth->secondsRemaining.
- */
-
-static CARD32
-SecurityAuthorizationExpired(
- OsTimerPtr timer,
- CARD32 time,
- pointer pval)
-{
- SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval;
-
- assert(pAuth->timer == timer);
-
- if (pAuth->secondsRemaining)
- {
- return SecurityComputeAuthorizationTimeout(pAuth,
- pAuth->secondsRemaining);
- }
- else
- {
- FreeResource(pAuth->id, RT_NONE);
- return 0;
- }
-} /* SecurityAuthorizationExpired */
-
-/* SecurityStartAuthorizationTimer
- *
- * Arguments:
- * pAuth is the authorization whose timer should be started.
- *
- * Returns: nothing.
- *
- * Side Effects:
- * A timer is started, set to expire after the timeout period for
- * this authorization. When it expires, the function
- * SecurityAuthorizationExpired will be called.
- */
-
-static void
-SecurityStartAuthorizationTimer(
- SecurityAuthorizationPtr pAuth)
-{
- pAuth->timer = TimerSet(pAuth->timer, 0,
- SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout),
- SecurityAuthorizationExpired, pAuth);
-} /* SecurityStartAuthorizationTimer */
-
-
-/* Proc functions all take a client argument, execute the request in
- * client->requestBuffer, and return a protocol error status.
- */
-
-static int
-ProcSecurityQueryVersion(
- ClientPtr client)
-{
- /* REQUEST(xSecurityQueryVersionReq); */
- xSecurityQueryVersionReply rep;
-
- REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.majorVersion = SERVER_SECURITY_MAJOR_VERSION;
- rep.minorVersion = SERVER_SECURITY_MINOR_VERSION;
- if(client->swapped)
- {
- char n;
- swaps(&rep.sequenceNumber, n);
- swaps(&rep.majorVersion, n);
- swaps(&rep.minorVersion, n);
- }
- (void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply),
- (char *)&rep);
- return Success;
-} /* ProcSecurityQueryVersion */
-
-
-static int
-SecurityEventSelectForAuthorization(
- SecurityAuthorizationPtr pAuth,
- ClientPtr client,
- Mask mask)
-{
- OtherClients *pEventClient;
-
- for (pEventClient = pAuth->eventClients;
- pEventClient;
- pEventClient = pEventClient->next)
- {
- if (SameClient(pEventClient, client))
- {
- if (mask == 0)
- FreeResource(pEventClient->resource, RT_NONE);
- else
- pEventClient->mask = mask;
- return Success;
- }
- }
-
- pEventClient = malloc(sizeof(OtherClients));
- if (!pEventClient)
- return BadAlloc;
- pEventClient->mask = mask;
- pEventClient->resource = FakeClientID(client->index);
- pEventClient->next = pAuth->eventClients;
- if (!AddResource(pEventClient->resource, RTEventClient,
- (pointer)pAuth))
- {
- free(pEventClient);
- return BadAlloc;
- }
- pAuth->eventClients = pEventClient;
-
- return Success;
-} /* SecurityEventSelectForAuthorization */
-
-
-static int
-ProcSecurityGenerateAuthorization(
- ClientPtr client)
-{
- REQUEST(xSecurityGenerateAuthorizationReq);
- int len; /* request length in CARD32s*/
- Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */
- SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */
- int err; /* error to return from this function */
- XID authId; /* authorization ID assigned by os layer */
- xSecurityGenerateAuthorizationReply rep; /* reply struct */
- unsigned int trustLevel; /* trust level of new auth */
- XID group; /* group of new auth */
- CARD32 timeout; /* timeout of new auth */
- CARD32 *values; /* list of supplied attributes */
- char *protoname; /* auth proto name sent in request */
- char *protodata; /* auth proto data sent in request */
- unsigned int authdata_len; /* # bytes of generated auth data */
- char *pAuthdata; /* generated auth data */
- Mask eventMask; /* what events on this auth does client want */
-
- /* check request length */
-
- REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
- len = bytes_to_int32(SIZEOF(xSecurityGenerateAuthorizationReq));
- len += bytes_to_int32(stuff->nbytesAuthProto);
- len += bytes_to_int32(stuff->nbytesAuthData);
- values = ((CARD32 *)stuff) + len;
- len += Ones(stuff->valueMask);
- if (client->req_len != len)
- return BadLength;
-
- /* check valuemask */
- if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes)
- {
- client->errorValue = stuff->valueMask;
- return BadValue;
- }
-
- /* check timeout */
- timeout = 60;
- if (stuff->valueMask & XSecurityTimeout)
- {
- timeout = *values++;
- }
-
- /* check trustLevel */
- trustLevel = XSecurityClientUntrusted;
- if (stuff->valueMask & XSecurityTrustLevel)
- {
- trustLevel = *values++;
- if (trustLevel != XSecurityClientTrusted &&
- trustLevel != XSecurityClientUntrusted)
- {
- client->errorValue = trustLevel;
- return BadValue;
- }
- }
-
- /* check group */
- group = None;
- if (stuff->valueMask & XSecurityGroup)
- {
- group = *values++;
- if (SecurityValidateGroupCallback)
- {
- SecurityValidateGroupInfoRec vgi;
- vgi.group = group;
- vgi.valid = FALSE;
- CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi);
-
- /* if nobody said they recognized it, it's an error */
-
- if (!vgi.valid)
- {
- client->errorValue = group;
- return BadValue;
- }
- }
- }
-
- /* check event mask */
- eventMask = 0;
- if (stuff->valueMask & XSecurityEventMask)
- {
- eventMask = *values++;
- if (eventMask & ~XSecurityAllEventMasks)
- {
- client->errorValue = eventMask;
- return BadValue;
- }
- }
-
- protoname = (char *)&stuff[1];
- protodata = protoname + bytes_to_int32(stuff->nbytesAuthProto);
-
- /* call os layer to generate the authorization */
-
- authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname,
- stuff->nbytesAuthData, protodata,
- &authdata_len, &pAuthdata);
- if ((XID) ~0L == authId)
- {
- err = SecurityErrorBase + XSecurityBadAuthorizationProtocol;
- goto bailout;
- }
-
- /* now that we've added the auth, remember to remove it if we have to
- * abort the request for some reason (like allocation failure)
- */
- removeAuth = TRUE;
-
- /* associate additional information with this auth ID */
-
- pAuth = malloc(sizeof(SecurityAuthorizationRec));
- if (!pAuth)
- {
- err = BadAlloc;
- goto bailout;
- }
-
- /* fill in the auth fields */
-
- pAuth->id = authId;
- pAuth->timeout = timeout;
- pAuth->group = group;
- pAuth->trustLevel = trustLevel;
- pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */
- pAuth->secondsRemaining = 0;
- pAuth->timer = NULL;
- pAuth->eventClients = NULL;
-
- /* handle event selection */
- if (eventMask)
- {
- err = SecurityEventSelectForAuthorization(pAuth, client, eventMask);
- if (err != Success)
- goto bailout;
- }
-
- if (!AddResource(authId, SecurityAuthorizationResType, pAuth))
- {
- err = BadAlloc;
- goto bailout;
- }
-
- /* start the timer ticking */
-
- if (pAuth->timeout != 0)
- SecurityStartAuthorizationTimer(pAuth);
-
- /* tell client the auth id and data */
-
- rep.type = X_Reply;
- rep.length = bytes_to_int32(authdata_len);
- rep.sequenceNumber = client->sequence;
- rep.authId = authId;
- rep.dataLength = authdata_len;
-
- if (client->swapped)
- {
- char n;
- swapl(&rep.length, n);
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.authId, n);
- swaps(&rep.dataLength, n);
- }
-
- WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply),
- (char *)&rep);
- WriteToClient(client, authdata_len, pAuthdata);
-
- SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n",
- client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout,
- pAuth->group, eventMask);
-
- /* the request succeeded; don't call RemoveAuthorization or free pAuth */
- return Success;
-
-bailout:
- if (removeAuth)
- RemoveAuthorization(stuff->nbytesAuthProto, protoname,
- authdata_len, pAuthdata);
- free(pAuth);
- return err;
-
-} /* ProcSecurityGenerateAuthorization */
-
-static int
-ProcSecurityRevokeAuthorization(
- ClientPtr client)
-{
- REQUEST(xSecurityRevokeAuthorizationReq);
- SecurityAuthorizationPtr pAuth;
- int rc;
-
- REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
-
- rc = dixLookupResourceByType((pointer *)&pAuth, stuff->authId,
- SecurityAuthorizationResType, client,
- DixDestroyAccess);
- if (rc != Success)
- return rc;
-
- FreeResource(stuff->authId, RT_NONE);
- return Success;
-} /* ProcSecurityRevokeAuthorization */
-
-
-static int
-ProcSecurityDispatch(
- ClientPtr client)
-{
- REQUEST(xReq);
-
- switch (stuff->data)
- {
- case X_SecurityQueryVersion:
- return ProcSecurityQueryVersion(client);
- case X_SecurityGenerateAuthorization:
- return ProcSecurityGenerateAuthorization(client);
- case X_SecurityRevokeAuthorization:
- return ProcSecurityRevokeAuthorization(client);
- default:
- return BadRequest;
- }
-} /* ProcSecurityDispatch */
-
-static int
-SProcSecurityQueryVersion(
- ClientPtr client)
-{
- REQUEST(xSecurityQueryVersionReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
- swaps(&stuff->majorVersion, n);
- swaps(&stuff->minorVersion,n);
- return ProcSecurityQueryVersion(client);
-} /* SProcSecurityQueryVersion */
-
-
-static int
-SProcSecurityGenerateAuthorization(
- ClientPtr client)
-{
- REQUEST(xSecurityGenerateAuthorizationReq);
- char n;
- CARD32 *values;
- unsigned long nvalues;
- int values_offset;
-
- swaps(&stuff->length, n);
- REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq);
- swaps(&stuff->nbytesAuthProto, n);
- swaps(&stuff->nbytesAuthData, n);
- swapl(&stuff->valueMask, n);
- values_offset = bytes_to_int32(stuff->nbytesAuthProto) +
- bytes_to_int32(stuff->nbytesAuthData);
- if (values_offset >
- stuff->length - bytes_to_int32(sz_xSecurityGenerateAuthorizationReq))
- return BadLength;
- values = (CARD32 *)(&stuff[1]) + values_offset;
- nvalues = (((CARD32 *)stuff) + stuff->length) - values;
- SwapLongs(values, nvalues);
- return ProcSecurityGenerateAuthorization(client);
-} /* SProcSecurityGenerateAuthorization */
-
-
-static int
-SProcSecurityRevokeAuthorization(
- ClientPtr client)
-{
- REQUEST(xSecurityRevokeAuthorizationReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
- swapl(&stuff->authId, n);
- return ProcSecurityRevokeAuthorization(client);
-} /* SProcSecurityRevokeAuthorization */
-
-
-static int
-SProcSecurityDispatch(
- ClientPtr client)
-{
- REQUEST(xReq);
-
- switch (stuff->data)
- {
- case X_SecurityQueryVersion:
- return SProcSecurityQueryVersion(client);
- case X_SecurityGenerateAuthorization:
- return SProcSecurityGenerateAuthorization(client);
- case X_SecurityRevokeAuthorization:
- return SProcSecurityRevokeAuthorization(client);
- default:
- return BadRequest;
- }
-} /* SProcSecurityDispatch */
-
-static void
-SwapSecurityAuthorizationRevokedEvent(
- xSecurityAuthorizationRevokedEvent *from,
- xSecurityAuthorizationRevokedEvent *to)
-{
- to->type = from->type;
- to->detail = from->detail;
- cpswaps(from->sequenceNumber, to->sequenceNumber);
- cpswapl(from->authId, to->authId);
-}
-
-/* SecurityCheckDeviceAccess
- *
- * Arguments:
- * client is the client attempting to access a device.
- * dev is the device being accessed.
- * fromRequest is TRUE if the device access is a direct result of
- * the client executing some request and FALSE if it is a
- * result of the server trying to send an event (e.g. KeymapNotify)
- * to the client.
- * Returns:
- * TRUE if the device access should be allowed, else FALSE.
- *
- * Side Effects:
- * An audit message is generated if access is denied.
- */
-
-static void
-SecurityDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceDeviceAccessRec *rec = calldata;
- SecurityStateRec *subj, *obj;
- Mask requested = rec->access_mode;
- Mask allowed = SecurityDeviceMask;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
- obj = dixLookupPrivate(&serverClient->devPrivates, stateKey);
-
- if (rec->dev != inputInfo.keyboard)
- /* this extension only supports the core keyboard */
- allowed = requested;
-
- if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
- SecurityAudit("Security denied client %d keyboard access on request "
- "%s\n", rec->client->index,
- SecurityLookupRequestName(rec->client));
- rec->status = BadAccess;
- }
-}
-
-/* SecurityResource
- *
- * This function gets plugged into client->CheckAccess and is called from
- * SecurityLookupIDByType/Class to determine if the client can access the
- * resource.
- *
- * Arguments:
- * client is the client doing the resource access.
- * id is the resource id.
- * rtype is its type or class.
- * access_mode represents the intended use of the resource; see
- * resource.h.
- * res is a pointer to the resource structure for this resource.
- *
- * Returns:
- * If access is granted, the value of rval that was passed in, else FALSE.
- *
- * Side Effects:
- * Disallowed resource accesses are audited.
- */
-
-static void
-SecurityResource(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceResourceAccessRec *rec = calldata;
- SecurityStateRec *subj, *obj;
- int cid = CLIENT_ID(rec->id);
- Mask requested = rec->access_mode;
- Mask allowed = SecurityResourceMask;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
-
- /* disable background None for untrusted windows */
- if ((requested & DixCreateAccess) && (rec->rtype == RT_WINDOW))
- if (subj->haveState && subj->trustLevel != XSecurityClientTrusted)
- ((WindowPtr)rec->res)->forcedBG = TRUE;
-
- /* additional permissions for specific resource types */
- if (rec->rtype == RT_WINDOW)
- allowed |= SecurityWindowExtraMask;
-
- /* special checks for server-owned resources */
- if (cid == 0) {
- if (rec->rtype & RC_DRAWABLE)
- /* additional operations allowed on root windows */
- allowed |= SecurityRootWindowExtraMask;
-
- else if (rec->rtype == RT_COLORMAP)
- /* allow access to default colormaps */
- allowed = requested;
-
- else
- /* allow read access to other server-owned resources */
- allowed |= DixReadAccess;
- }
-
- if (clients[cid] != NULL) {
- obj = dixLookupPrivate(&clients[cid]->devPrivates, stateKey);
- if (SecurityDoCheck(subj, obj, requested, allowed) == Success)
- return;
- }
-
- SecurityAudit("Security: denied client %d access %x to resource 0x%x "
- "of client %d on request %s\n", rec->client->index,
- requested, rec->id, cid,
- SecurityLookupRequestName(rec->client));
- rec->status = BadAccess; /* deny access */
-}
-
-
-static void
-SecurityExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceExtAccessRec *rec = calldata;
- SecurityStateRec *subj;
- int i = 0;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
-
- if (subj->haveState && subj->trustLevel == XSecurityClientTrusted)
- return;
-
- while (SecurityTrustedExtensions[i])
- if (!strcmp(SecurityTrustedExtensions[i++], rec->ext->name))
- return;
-
- SecurityAudit("Security: denied client %d access to extension "
- "%s on request %s\n",
- rec->client->index, rec->ext->name,
- SecurityLookupRequestName(rec->client));
- rec->status = BadAccess;
-}
-
-static void
-SecurityServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceServerAccessRec *rec = calldata;
- SecurityStateRec *subj, *obj;
- Mask requested = rec->access_mode;
- Mask allowed = SecurityServerMask;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
- obj = dixLookupPrivate(&serverClient->devPrivates, stateKey);
-
- if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
- SecurityAudit("Security: denied client %d access to server "
- "configuration request %s\n", rec->client->index,
- SecurityLookupRequestName(rec->client));
- rec->status = BadAccess;
- }
-}
-
-static void
-SecurityClient(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceClientAccessRec *rec = calldata;
- SecurityStateRec *subj, *obj;
- Mask requested = rec->access_mode;
- Mask allowed = SecurityClientMask;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
- obj = dixLookupPrivate(&rec->target->devPrivates, stateKey);
-
- if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
- SecurityAudit("Security: denied client %d access to client %d on "
- "request %s\n", rec->client->index, rec->target->index,
- SecurityLookupRequestName(rec->client));
- rec->status = BadAccess;
- }
-}
-
-static void
-SecurityProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XacePropertyAccessRec *rec = calldata;
- SecurityStateRec *subj, *obj;
- ATOM name = (*rec->ppProp)->propertyName;
- Mask requested = rec->access_mode;
- Mask allowed = SecurityResourceMask | DixReadAccess;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
- obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
-
- if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
- SecurityAudit("Security: denied client %d access to property %s "
- "(atom 0x%x) window 0x%x of client %d on request %s\n",
- rec->client->index, NameForAtom(name), name,
- rec->pWin->drawable.id, wClient(rec->pWin)->index,
- SecurityLookupRequestName(rec->client));
- rec->status = BadAccess;
- }
-}
-
-static void
-SecuritySend(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceSendAccessRec *rec = calldata;
- SecurityStateRec *subj, *obj;
-
- if (rec->client) {
- int i;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
- obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
-
- if (SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success)
- return;
-
- for (i = 0; i < rec->count; i++)
- if (rec->events[i].u.u.type != UnmapNotify &&
- rec->events[i].u.u.type != ConfigureRequest &&
- rec->events[i].u.u.type != ClientMessage) {
-
- SecurityAudit("Security: denied client %d from sending event "
- "of type %s to window 0x%x of client %d\n",
- rec->client->index,
- LookupEventName(rec->events[i].u.u.type),
- rec->pWin->drawable.id,
- wClient(rec->pWin)->index);
- rec->status = BadAccess;
- return;
- }
- }
-}
-
-static void
-SecurityReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceReceiveAccessRec *rec = calldata;
- SecurityStateRec *subj, *obj;
-
- subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
- obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
-
- if (SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success)
- return;
-
- SecurityAudit("Security: denied client %d from receiving an event "
- "sent to window 0x%x of client %d\n",
- rec->client->index, rec->pWin->drawable.id,
- wClient(rec->pWin)->index);
- rec->status = BadAccess;
-}
-
-/* SecurityClientStateCallback
- *
- * Arguments:
- * pcbl is &ClientStateCallback.
- * nullata is NULL.
- * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
- * which contains information about client state changes.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *
- * If a new client is connecting, its authorization ID is copied to
- * client->authID. If this is a generated authorization, its reference
- * count is bumped, its timer is cancelled if it was running, and its
- * trustlevel is copied to TRUSTLEVEL(client).
- *
- * If a client is disconnecting and the client was using a generated
- * authorization, the authorization's reference count is decremented, and
- * if it is now zero, the timer for this authorization is started.
- */
-
-static void
-SecurityClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- NewClientInfoRec *pci = calldata;
- SecurityStateRec *state;
- SecurityAuthorizationPtr pAuth;
- int rc;
-
- state = dixLookupPrivate(&pci->client->devPrivates, stateKey);
-
- switch (pci->client->clientState) {
- case ClientStateInitial:
- state->trustLevel = XSecurityClientTrusted;
- state->authId = None;
- state->haveState = TRUE;
- break;
-
- case ClientStateRunning:
- state->authId = AuthorizationIDOfClient(pci->client);
- rc = dixLookupResourceByType((pointer *)&pAuth, state->authId,
- SecurityAuthorizationResType, serverClient,
- DixGetAttrAccess);
- if (rc == Success) {
- /* it is a generated authorization */
- pAuth->refcnt++;
- if (pAuth->refcnt == 1 && pAuth->timer)
- TimerCancel(pAuth->timer);
-
- state->trustLevel = pAuth->trustLevel;
- }
- break;
-
- case ClientStateGone:
- case ClientStateRetained:
- rc = dixLookupResourceByType((pointer *)&pAuth, state->authId,
- SecurityAuthorizationResType, serverClient,
- DixGetAttrAccess);
- if (rc == Success) {
- /* it is a generated authorization */
- pAuth->refcnt--;
- if (pAuth->refcnt == 0)
- SecurityStartAuthorizationTimer(pAuth);
- }
- break;
-
- default:
- break;
- }
-}
-
-/* SecurityResetProc
- *
- * Arguments:
- * extEntry is the extension information for the security extension.
- *
- * Returns: nothing.
- *
- * Side Effects:
- * Performs any cleanup needed by Security at server shutdown time.
- */
-
-static void
-SecurityResetProc(
- ExtensionEntry *extEntry)
-{
- /* Unregister callbacks */
- DeleteCallback(&ClientStateCallback, SecurityClientState, NULL);
-
- XaceDeleteCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL);
- XaceDeleteCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL);
- XaceDeleteCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL);
- XaceDeleteCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL);
- XaceDeleteCallback(XACE_SEND_ACCESS, SecuritySend, NULL);
- XaceDeleteCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL);
- XaceDeleteCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL);
- XaceDeleteCallback(XACE_EXT_ACCESS, SecurityExtension, NULL);
- XaceDeleteCallback(XACE_SERVER_ACCESS, SecurityServer, NULL);
-}
-
-
-/* SecurityExtensionInit
- *
- * Arguments: none.
- *
- * Returns: nothing.
- *
- * Side Effects:
- * Enables the Security extension if possible.
- */
-
-void
-SecurityExtensionInit(INITARGS)
-{
- ExtensionEntry *extEntry;
- int ret = TRUE;
-
- SecurityAuthorizationResType =
- CreateNewResourceType(SecurityDeleteAuthorization,
- "SecurityAuthorization");
-
- RTEventClient =
- CreateNewResourceType(SecurityDeleteAuthorizationEventClient,
- "SecurityEventClient");
-
- if (!SecurityAuthorizationResType || !RTEventClient)
- return;
-
- RTEventClient |= RC_NEVERRETAIN;
-
- /* Allocate the private storage */
- if (!dixRegisterPrivateKey(stateKey, PRIVATE_CLIENT, sizeof(SecurityStateRec)))
- FatalError("SecurityExtensionSetup: Can't allocate client private.\n");
-
- /* Register callbacks */
- ret &= AddCallback(&ClientStateCallback, SecurityClientState, NULL);
-
- ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL);
- ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL);
- ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL);
- ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL);
- ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SecuritySend, NULL);
- ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL);
- ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL);
- ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SecurityExtension, NULL);
- ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SecurityServer, NULL);
-
- if (!ret)
- FatalError("SecurityExtensionSetup: Failed to register callbacks\n");
-
- /* Add extension to server */
- extEntry = AddExtension(SECURITY_EXTENSION_NAME,
- XSecurityNumberEvents, XSecurityNumberErrors,
- ProcSecurityDispatch, SProcSecurityDispatch,
- SecurityResetProc, StandardMinorOpcode);
-
- SecurityErrorBase = extEntry->errorBase;
- SecurityEventBase = extEntry->eventBase;
-
- EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] =
- (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent;
-
- SetResourceTypeErrorValue(SecurityAuthorizationResType, SecurityErrorBase + XSecurityBadAuthorization);
-
- /* Label objects that were created before we could register ourself */
- SecurityLabelInitial();
-}
+/* + +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "scrnintstr.h" +#include "inputstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "colormapst.h" +#include "privates.h" +#include "registry.h" +#include "xacestr.h" +#include "securitysrv.h" +#include <X11/extensions/securproto.h> +#include "modinit.h" +#include "protocol-versions.h" + +/* Extension stuff */ +static int SecurityErrorBase; /* first Security error number */ +static int SecurityEventBase; /* first Security event number */ + +RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */ +static RESTYPE RTEventClient; + +static CallbackListPtr SecurityValidateGroupCallback = NULL; + +/* Private state record */ +static DevPrivateKeyRec stateKeyRec; +#define stateKey (&stateKeyRec) + +/* This is what we store as client security state */ +typedef struct { + int haveState; + unsigned int trustLevel; + XID authId; +} SecurityStateRec; + +/* Extensions that untrusted clients shouldn't have access to */ +static char *SecurityTrustedExtensions[] = { + "XC-MISC", + "BIG-REQUESTS", + "XpExtension", + NULL +}; + +/* + * Access modes that untrusted clients are allowed on trusted objects. + */ +static const Mask SecurityResourceMask = + DixGetAttrAccess | DixReceiveAccess | DixListPropAccess | + DixGetPropAccess | DixListAccess; +static const Mask SecurityWindowExtraMask = DixRemoveAccess; +static const Mask SecurityRootWindowExtraMask = + DixReceiveAccess | DixSendAccess | DixAddAccess | DixRemoveAccess; +static const Mask SecurityDeviceMask = + DixGetAttrAccess | DixReceiveAccess | DixGetFocusAccess | + DixGrabAccess | DixSetAttrAccess | DixUseAccess; +static const Mask SecurityServerMask = DixGetAttrAccess | DixGrabAccess; +static const Mask SecurityClientMask = DixGetAttrAccess; + + +/* SecurityAudit + * + * Arguments: + * format is the formatting string to be used to interpret the + * remaining arguments. + * + * Returns: nothing. + * + * Side Effects: + * Writes the message to the log file if security logging is on. + */ + +static void +SecurityAudit(char *format, ...) +{ + va_list args; + + if (auditTrailLevel < SECURITY_AUDIT_LEVEL) + return; + va_start(args, format); + VAuditF(format, args); + va_end(args); +} /* SecurityAudit */ + +/* + * Performs a Security permission check. + */ +static int +SecurityDoCheck(SecurityStateRec *subj, SecurityStateRec *obj, + Mask requested, Mask allowed) +{ + if (!subj->haveState || !obj->haveState) + return Success; + if (subj->trustLevel == XSecurityClientTrusted) + return Success; + if (obj->trustLevel != XSecurityClientTrusted) + return Success; + if ((requested | allowed) == allowed) + return Success; + + return BadAccess; +} + +/* + * Labels initial server objects. + */ +static void +SecurityLabelInitial(void) +{ + SecurityStateRec *state; + + /* Do the serverClient */ + state = dixLookupPrivate(&serverClient->devPrivates, stateKey); + state->trustLevel = XSecurityClientTrusted; + state->haveState = TRUE; +} + +/* + * Looks up a request name + */ +static _X_INLINE const char * +SecurityLookupRequestName(ClientPtr client) +{ + int major = ((xReq *)client->requestBuffer)->reqType; + int minor = MinorOpcodeOfRequest(client); + return LookupRequestName(major, minor); +} + + +/* SecurityDeleteAuthorization + * + * Arguments: + * value is the authorization to delete. + * id is its resource ID. + * + * Returns: Success. + * + * Side Effects: + * Frees everything associated with the authorization. + */ + +static int +SecurityDeleteAuthorization( + pointer value, + XID id) +{ + SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; + unsigned short name_len, data_len; + char *name, *data; + int status; + int i; + OtherClientsPtr pEventClient; + + /* Remove the auth using the os layer auth manager */ + + status = AuthorizationFromID(pAuth->id, &name_len, &name, + &data_len, &data); + assert(status); + status = RemoveAuthorization(name_len, name, data_len, data); + assert(status); + (void)status; + + /* free the auth timer if there is one */ + + if (pAuth->timer) TimerFree(pAuth->timer); + + /* send revoke events */ + + while ((pEventClient = pAuth->eventClients)) + { + /* send revocation event event */ + xSecurityAuthorizationRevokedEvent are; + are.type = SecurityEventBase + XSecurityAuthorizationRevoked; + are.authId = pAuth->id; + WriteEventsToClient(rClient(pEventClient), 1, (xEvent *)&are); + FreeResource(pEventClient->resource, RT_NONE); + } + + /* kill all clients using this auth */ + + for (i = 1; i<currentMaxClients; i++) + if (clients[i]) { + SecurityStateRec *state; + state = dixLookupPrivate(&clients[i]->devPrivates, stateKey); + if (state->haveState && state->authId == pAuth->id) + CloseDownClient(clients[i]); + } + + SecurityAudit("revoked authorization ID %d\n", pAuth->id); + free(pAuth); + return Success; + +} /* SecurityDeleteAuthorization */ + + +/* resource delete function for RTEventClient */ +static int +SecurityDeleteAuthorizationEventClient( + pointer value, + XID id) +{ + OtherClientsPtr pEventClient, prev = NULL; + SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; + + for (pEventClient = pAuth->eventClients; + pEventClient; + pEventClient = pEventClient->next) + { + if (pEventClient->resource == id) + { + if (prev) + prev->next = pEventClient->next; + else + pAuth->eventClients = pEventClient->next; + free(pEventClient); + return Success; + } + prev = pEventClient; + } + /*NOTREACHED*/ + return -1; /* make compiler happy */ +} /* SecurityDeleteAuthorizationEventClient */ + + +/* SecurityComputeAuthorizationTimeout + * + * Arguments: + * pAuth is the authorization for which we are computing the timeout + * seconds is the number of seconds we want to wait + * + * Returns: + * the number of milliseconds that the auth timer should be set to + * + * Side Effects: + * Sets pAuth->secondsRemaining to any "overflow" amount of time + * that didn't fit in 32 bits worth of milliseconds + */ + +static CARD32 +SecurityComputeAuthorizationTimeout( + SecurityAuthorizationPtr pAuth, + unsigned int seconds) +{ + /* maxSecs is the number of full seconds that can be expressed in + * 32 bits worth of milliseconds + */ + CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND; + + if (seconds > maxSecs) + { /* only come here if we want to wait more than 49 days */ + pAuth->secondsRemaining = seconds - maxSecs; + return maxSecs * MILLI_PER_SECOND; + } + else + { /* by far the common case */ + pAuth->secondsRemaining = 0; + return seconds * MILLI_PER_SECOND; + } +} /* SecurityStartAuthorizationTimer */ + +/* SecurityAuthorizationExpired + * + * This function is passed as an argument to TimerSet and gets called from + * the timer manager in the os layer when its time is up. + * + * Arguments: + * timer is the timer for this authorization. + * time is the current time. + * pval is the authorization whose time is up. + * + * Returns: + * A new time delay in milliseconds if the timer should wait some + * more, else zero. + * + * Side Effects: + * Frees the authorization resource if the timeout period is really + * over, otherwise recomputes pAuth->secondsRemaining. + */ + +static CARD32 +SecurityAuthorizationExpired( + OsTimerPtr timer, + CARD32 time, + pointer pval) +{ + SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval; + + assert(pAuth->timer == timer); + + if (pAuth->secondsRemaining) + { + return SecurityComputeAuthorizationTimeout(pAuth, + pAuth->secondsRemaining); + } + else + { + FreeResource(pAuth->id, RT_NONE); + return 0; + } +} /* SecurityAuthorizationExpired */ + +/* SecurityStartAuthorizationTimer + * + * Arguments: + * pAuth is the authorization whose timer should be started. + * + * Returns: nothing. + * + * Side Effects: + * A timer is started, set to expire after the timeout period for + * this authorization. When it expires, the function + * SecurityAuthorizationExpired will be called. + */ + +static void +SecurityStartAuthorizationTimer( + SecurityAuthorizationPtr pAuth) +{ + pAuth->timer = TimerSet(pAuth->timer, 0, + SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout), + SecurityAuthorizationExpired, pAuth); +} /* SecurityStartAuthorizationTimer */ + + +/* Proc functions all take a client argument, execute the request in + * client->requestBuffer, and return a protocol error status. + */ + +static int +ProcSecurityQueryVersion( + ClientPtr client) +{ + /* REQUEST(xSecurityQueryVersionReq); */ + xSecurityQueryVersionReply rep; + + REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.majorVersion = SERVER_SECURITY_MAJOR_VERSION; + rep.minorVersion = SERVER_SECURITY_MINOR_VERSION; + if(client->swapped) + { + swaps(&rep.sequenceNumber); + swaps(&rep.majorVersion); + swaps(&rep.minorVersion); + } + (void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply), + (char *)&rep); + return Success; +} /* ProcSecurityQueryVersion */ + + +static int +SecurityEventSelectForAuthorization( + SecurityAuthorizationPtr pAuth, + ClientPtr client, + Mask mask) +{ + OtherClients *pEventClient; + + for (pEventClient = pAuth->eventClients; + pEventClient; + pEventClient = pEventClient->next) + { + if (SameClient(pEventClient, client)) + { + if (mask == 0) + FreeResource(pEventClient->resource, RT_NONE); + else + pEventClient->mask = mask; + return Success; + } + } + + pEventClient = malloc(sizeof(OtherClients)); + if (!pEventClient) + return BadAlloc; + pEventClient->mask = mask; + pEventClient->resource = FakeClientID(client->index); + pEventClient->next = pAuth->eventClients; + if (!AddResource(pEventClient->resource, RTEventClient, + (pointer)pAuth)) + { + free(pEventClient); + return BadAlloc; + } + pAuth->eventClients = pEventClient; + + return Success; +} /* SecurityEventSelectForAuthorization */ + + +static int +ProcSecurityGenerateAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityGenerateAuthorizationReq); + int len; /* request length in CARD32s*/ + Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */ + SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */ + int err; /* error to return from this function */ + XID authId; /* authorization ID assigned by os layer */ + xSecurityGenerateAuthorizationReply rep; /* reply struct */ + unsigned int trustLevel; /* trust level of new auth */ + XID group; /* group of new auth */ + CARD32 timeout; /* timeout of new auth */ + CARD32 *values; /* list of supplied attributes */ + char *protoname; /* auth proto name sent in request */ + char *protodata; /* auth proto data sent in request */ + unsigned int authdata_len; /* # bytes of generated auth data */ + char *pAuthdata; /* generated auth data */ + Mask eventMask; /* what events on this auth does client want */ + + /* check request length */ + + REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); + len = bytes_to_int32(SIZEOF(xSecurityGenerateAuthorizationReq)); + len += bytes_to_int32(stuff->nbytesAuthProto); + len += bytes_to_int32(stuff->nbytesAuthData); + values = ((CARD32 *)stuff) + len; + len += Ones(stuff->valueMask); + if (client->req_len != len) + return BadLength; + + /* check valuemask */ + if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes) + { + client->errorValue = stuff->valueMask; + return BadValue; + } + + /* check timeout */ + timeout = 60; + if (stuff->valueMask & XSecurityTimeout) + { + timeout = *values++; + } + + /* check trustLevel */ + trustLevel = XSecurityClientUntrusted; + if (stuff->valueMask & XSecurityTrustLevel) + { + trustLevel = *values++; + if (trustLevel != XSecurityClientTrusted && + trustLevel != XSecurityClientUntrusted) + { + client->errorValue = trustLevel; + return BadValue; + } + } + + /* check group */ + group = None; + if (stuff->valueMask & XSecurityGroup) + { + group = *values++; + if (SecurityValidateGroupCallback) + { + SecurityValidateGroupInfoRec vgi; + vgi.group = group; + vgi.valid = FALSE; + CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi); + + /* if nobody said they recognized it, it's an error */ + + if (!vgi.valid) + { + client->errorValue = group; + return BadValue; + } + } + } + + /* check event mask */ + eventMask = 0; + if (stuff->valueMask & XSecurityEventMask) + { + eventMask = *values++; + if (eventMask & ~XSecurityAllEventMasks) + { + client->errorValue = eventMask; + return BadValue; + } + } + + protoname = (char *)&stuff[1]; + protodata = protoname + bytes_to_int32(stuff->nbytesAuthProto); + + /* call os layer to generate the authorization */ + + authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname, + stuff->nbytesAuthData, protodata, + &authdata_len, &pAuthdata); + if ((XID) ~0L == authId) + { + err = SecurityErrorBase + XSecurityBadAuthorizationProtocol; + goto bailout; + } + + /* now that we've added the auth, remember to remove it if we have to + * abort the request for some reason (like allocation failure) + */ + removeAuth = TRUE; + + /* associate additional information with this auth ID */ + + pAuth = malloc(sizeof(SecurityAuthorizationRec)); + if (!pAuth) + { + err = BadAlloc; + goto bailout; + } + + /* fill in the auth fields */ + + pAuth->id = authId; + pAuth->timeout = timeout; + pAuth->group = group; + pAuth->trustLevel = trustLevel; + pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */ + pAuth->secondsRemaining = 0; + pAuth->timer = NULL; + pAuth->eventClients = NULL; + + /* handle event selection */ + if (eventMask) + { + err = SecurityEventSelectForAuthorization(pAuth, client, eventMask); + if (err != Success) + goto bailout; + } + + if (!AddResource(authId, SecurityAuthorizationResType, pAuth)) + { + err = BadAlloc; + goto bailout; + } + + /* start the timer ticking */ + + if (pAuth->timeout != 0) + SecurityStartAuthorizationTimer(pAuth); + + /* tell client the auth id and data */ + + rep.type = X_Reply; + rep.length = bytes_to_int32(authdata_len); + rep.sequenceNumber = client->sequence; + rep.authId = authId; + rep.dataLength = authdata_len; + + if (client->swapped) + { + swapl(&rep.length); + swaps(&rep.sequenceNumber); + swapl(&rep.authId); + swaps(&rep.dataLength); + } + + WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply), + (char *)&rep); + WriteToClient(client, authdata_len, pAuthdata); + + SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n", + client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout, + pAuth->group, eventMask); + + /* the request succeeded; don't call RemoveAuthorization or free pAuth */ + return Success; + +bailout: + if (removeAuth) + RemoveAuthorization(stuff->nbytesAuthProto, protoname, + authdata_len, pAuthdata); + free(pAuth); + return err; + +} /* ProcSecurityGenerateAuthorization */ + +static int +ProcSecurityRevokeAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityRevokeAuthorizationReq); + SecurityAuthorizationPtr pAuth; + int rc; + + REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); + + rc = dixLookupResourceByType((pointer *)&pAuth, stuff->authId, + SecurityAuthorizationResType, client, + DixDestroyAccess); + if (rc != Success) + return rc; + + FreeResource(stuff->authId, RT_NONE); + return Success; +} /* ProcSecurityRevokeAuthorization */ + + +static int +ProcSecurityDispatch( + ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_SecurityQueryVersion: + return ProcSecurityQueryVersion(client); + case X_SecurityGenerateAuthorization: + return ProcSecurityGenerateAuthorization(client); + case X_SecurityRevokeAuthorization: + return ProcSecurityRevokeAuthorization(client); + default: + return BadRequest; + } +} /* ProcSecurityDispatch */ + +static int +SProcSecurityQueryVersion( + ClientPtr client) +{ + REQUEST(xSecurityQueryVersionReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); + swaps(&stuff->majorVersion); + swaps(&stuff->minorVersion); + return ProcSecurityQueryVersion(client); +} /* SProcSecurityQueryVersion */ + + +static int +SProcSecurityGenerateAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityGenerateAuthorizationReq); + CARD32 *values; + unsigned long nvalues; + int values_offset; + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); + swaps(&stuff->nbytesAuthProto); + swaps(&stuff->nbytesAuthData); + swapl(&stuff->valueMask); + values_offset = bytes_to_int32(stuff->nbytesAuthProto) + + bytes_to_int32(stuff->nbytesAuthData); + if (values_offset > + stuff->length - bytes_to_int32(sz_xSecurityGenerateAuthorizationReq)) + return BadLength; + values = (CARD32 *)(&stuff[1]) + values_offset; + nvalues = (((CARD32 *)stuff) + stuff->length) - values; + SwapLongs(values, nvalues); + return ProcSecurityGenerateAuthorization(client); +} /* SProcSecurityGenerateAuthorization */ + + +static int +SProcSecurityRevokeAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityRevokeAuthorizationReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); + swapl(&stuff->authId); + return ProcSecurityRevokeAuthorization(client); +} /* SProcSecurityRevokeAuthorization */ + + +static int +SProcSecurityDispatch( + ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_SecurityQueryVersion: + return SProcSecurityQueryVersion(client); + case X_SecurityGenerateAuthorization: + return SProcSecurityGenerateAuthorization(client); + case X_SecurityRevokeAuthorization: + return SProcSecurityRevokeAuthorization(client); + default: + return BadRequest; + } +} /* SProcSecurityDispatch */ + +static void +SwapSecurityAuthorizationRevokedEvent( + xSecurityAuthorizationRevokedEvent *from, + xSecurityAuthorizationRevokedEvent *to) +{ + to->type = from->type; + to->detail = from->detail; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->authId, to->authId); +} + +/* SecurityCheckDeviceAccess + * + * Arguments: + * client is the client attempting to access a device. + * dev is the device being accessed. + * fromRequest is TRUE if the device access is a direct result of + * the client executing some request and FALSE if it is a + * result of the server trying to send an event (e.g. KeymapNotify) + * to the client. + * Returns: + * TRUE if the device access should be allowed, else FALSE. + * + * Side Effects: + * An audit message is generated if access is denied. + */ + +static void +SecurityDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceDeviceAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityDeviceMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&serverClient->devPrivates, stateKey); + + if (rec->dev != inputInfo.keyboard) + /* this extension only supports the core keyboard */ + allowed = requested; + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security denied client %d keyboard access on request " + "%s\n", rec->client->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +/* SecurityResource + * + * This function gets plugged into client->CheckAccess and is called from + * SecurityLookupIDByType/Class to determine if the client can access the + * resource. + * + * Arguments: + * client is the client doing the resource access. + * id is the resource id. + * rtype is its type or class. + * access_mode represents the intended use of the resource; see + * resource.h. + * res is a pointer to the resource structure for this resource. + * + * Returns: + * If access is granted, the value of rval that was passed in, else FALSE. + * + * Side Effects: + * Disallowed resource accesses are audited. + */ + +static void +SecurityResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceResourceAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + int cid = CLIENT_ID(rec->id); + Mask requested = rec->access_mode; + Mask allowed = SecurityResourceMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + + /* disable background None for untrusted windows */ + if ((requested & DixCreateAccess) && (rec->rtype == RT_WINDOW)) + if (subj->haveState && subj->trustLevel != XSecurityClientTrusted) + ((WindowPtr)rec->res)->forcedBG = TRUE; + + /* additional permissions for specific resource types */ + if (rec->rtype == RT_WINDOW) + allowed |= SecurityWindowExtraMask; + + /* special checks for server-owned resources */ + if (cid == 0) { + if (rec->rtype & RC_DRAWABLE) + /* additional operations allowed on root windows */ + allowed |= SecurityRootWindowExtraMask; + + else if (rec->rtype == RT_COLORMAP) + /* allow access to default colormaps */ + allowed = requested; + + else + /* allow read access to other server-owned resources */ + allowed |= DixReadAccess; + } + + if (clients[cid] != NULL) { + obj = dixLookupPrivate(&clients[cid]->devPrivates, stateKey); + if (SecurityDoCheck(subj, obj, requested, allowed) == Success) + return; + } + + SecurityAudit("Security: denied client %d access %x to resource 0x%x " + "of client %d on request %s\n", rec->client->index, + requested, rec->id, cid, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; /* deny access */ +} + + +static void +SecurityExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceExtAccessRec *rec = calldata; + SecurityStateRec *subj; + int i = 0; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + + if (subj->haveState && subj->trustLevel == XSecurityClientTrusted) + return; + + while (SecurityTrustedExtensions[i]) + if (!strcmp(SecurityTrustedExtensions[i++], rec->ext->name)) + return; + + SecurityAudit("Security: denied client %d access to extension " + "%s on request %s\n", + rec->client->index, rec->ext->name, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; +} + +static void +SecurityServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceServerAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityServerMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&serverClient->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security: denied client %d access to server " + "configuration request %s\n", rec->client->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +static void +SecurityClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceClientAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityClientMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&rec->target->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security: denied client %d access to client %d on " + "request %s\n", rec->client->index, rec->target->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +static void +SecurityProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XacePropertyAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + ATOM name = (*rec->ppProp)->propertyName; + Mask requested = rec->access_mode; + Mask allowed = SecurityResourceMask | DixReadAccess; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security: denied client %d access to property %s " + "(atom 0x%x) window 0x%x of client %d on request %s\n", + rec->client->index, NameForAtom(name), name, + rec->pWin->drawable.id, wClient(rec->pWin)->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +static void +SecuritySend(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceSendAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + + if (rec->client) { + int i; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success) + return; + + for (i = 0; i < rec->count; i++) + if (rec->events[i].u.u.type != UnmapNotify && + rec->events[i].u.u.type != ConfigureRequest && + rec->events[i].u.u.type != ClientMessage) { + + SecurityAudit("Security: denied client %d from sending event " + "of type %s to window 0x%x of client %d\n", + rec->client->index, + LookupEventName(rec->events[i].u.u.type), + rec->pWin->drawable.id, + wClient(rec->pWin)->index); + rec->status = BadAccess; + return; + } + } +} + +static void +SecurityReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceReceiveAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success) + return; + + SecurityAudit("Security: denied client %d from receiving an event " + "sent to window 0x%x of client %d\n", + rec->client->index, rec->pWin->drawable.id, + wClient(rec->pWin)->index); + rec->status = BadAccess; +} + +/* SecurityClientStateCallback + * + * Arguments: + * pcbl is &ClientStateCallback. + * nullata is NULL. + * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h) + * which contains information about client state changes. + * + * Returns: nothing. + * + * Side Effects: + * + * If a new client is connecting, its authorization ID is copied to + * client->authID. If this is a generated authorization, its reference + * count is bumped, its timer is cancelled if it was running, and its + * trustlevel is copied to TRUSTLEVEL(client). + * + * If a client is disconnecting and the client was using a generated + * authorization, the authorization's reference count is decremented, and + * if it is now zero, the timer for this authorization is started. + */ + +static void +SecurityClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + NewClientInfoRec *pci = calldata; + SecurityStateRec *state; + SecurityAuthorizationPtr pAuth; + int rc; + + state = dixLookupPrivate(&pci->client->devPrivates, stateKey); + + switch (pci->client->clientState) { + case ClientStateInitial: + state->trustLevel = XSecurityClientTrusted; + state->authId = None; + state->haveState = TRUE; + break; + + case ClientStateRunning: + state->authId = AuthorizationIDOfClient(pci->client); + rc = dixLookupResourceByType((pointer *)&pAuth, state->authId, + SecurityAuthorizationResType, serverClient, + DixGetAttrAccess); + if (rc == Success) { + /* it is a generated authorization */ + pAuth->refcnt++; + if (pAuth->refcnt == 1 && pAuth->timer) + TimerCancel(pAuth->timer); + + state->trustLevel = pAuth->trustLevel; + } + break; + + case ClientStateGone: + case ClientStateRetained: + rc = dixLookupResourceByType((pointer *)&pAuth, state->authId, + SecurityAuthorizationResType, serverClient, + DixGetAttrAccess); + if (rc == Success) { + /* it is a generated authorization */ + pAuth->refcnt--; + if (pAuth->refcnt == 0) + SecurityStartAuthorizationTimer(pAuth); + } + break; + + default: + break; + } +} + +/* SecurityResetProc + * + * Arguments: + * extEntry is the extension information for the security extension. + * + * Returns: nothing. + * + * Side Effects: + * Performs any cleanup needed by Security at server shutdown time. + */ + +static void +SecurityResetProc( + ExtensionEntry *extEntry) +{ + /* Unregister callbacks */ + DeleteCallback(&ClientStateCallback, SecurityClientState, NULL); + + XaceDeleteCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL); + XaceDeleteCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL); + XaceDeleteCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL); + XaceDeleteCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL); + XaceDeleteCallback(XACE_SEND_ACCESS, SecuritySend, NULL); + XaceDeleteCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL); + XaceDeleteCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL); + XaceDeleteCallback(XACE_EXT_ACCESS, SecurityExtension, NULL); + XaceDeleteCallback(XACE_SERVER_ACCESS, SecurityServer, NULL); +} + + +/* SecurityExtensionInit + * + * Arguments: none. + * + * Returns: nothing. + * + * Side Effects: + * Enables the Security extension if possible. + */ + +void +SecurityExtensionInit(INITARGS) +{ + ExtensionEntry *extEntry; + int ret = TRUE; + + SecurityAuthorizationResType = + CreateNewResourceType(SecurityDeleteAuthorization, + "SecurityAuthorization"); + + RTEventClient = + CreateNewResourceType(SecurityDeleteAuthorizationEventClient, + "SecurityEventClient"); + + if (!SecurityAuthorizationResType || !RTEventClient) + return; + + RTEventClient |= RC_NEVERRETAIN; + + /* Allocate the private storage */ + if (!dixRegisterPrivateKey(stateKey, PRIVATE_CLIENT, sizeof(SecurityStateRec))) + FatalError("SecurityExtensionSetup: Can't allocate client private.\n"); + + /* Register callbacks */ + ret &= AddCallback(&ClientStateCallback, SecurityClientState, NULL); + + ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL); + ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL); + ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL); + ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL); + ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SecuritySend, NULL); + ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL); + ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL); + ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SecurityExtension, NULL); + ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SecurityServer, NULL); + + if (!ret) + FatalError("SecurityExtensionSetup: Failed to register callbacks\n"); + + /* Add extension to server */ + extEntry = AddExtension(SECURITY_EXTENSION_NAME, + XSecurityNumberEvents, XSecurityNumberErrors, + ProcSecurityDispatch, SProcSecurityDispatch, + SecurityResetProc, StandardMinorOpcode); + + SecurityErrorBase = extEntry->errorBase; + SecurityEventBase = extEntry->eventBase; + + EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] = + (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent; + + SetResourceTypeErrorValue(SecurityAuthorizationResType, SecurityErrorBase + XSecurityBadAuthorization); + + /* Label objects that were created before we could register ourself */ + SecurityLabelInitial(); +} |