diff options
author | Eamon Walsh <ewalsh@tycho.nsa.gov> | 2007-11-08 16:32:42 -0500 |
---|---|---|
committer | Eamon Walsh <ewalsh@moss-charon.epoch.ncsc.mil> | 2007-11-08 16:32:42 -0500 |
commit | 8b5d21cc1d1f4e9d20e5d5eca44cb1e60a419763 (patch) | |
tree | 20e21e8461bc1f17630ce10a2d435b99e627d001 | |
parent | a52c9b2a59f27266557ff9d5d2c08492e04135a6 (diff) |
Rework of the XC-SECURITY extension. The gen-auth protocol has not changed,
but the XC-QUERY-SECURITY-1 authorization method and the SecurityPolicy
configuration file have been removed. The semantics of the trusted vs.
untrusted split have been changed. This will be documented in a future
commit.
-rw-r--r-- | Xext/security.c | 1344 | ||||
-rw-r--r-- | Xext/securitysrv.h | 4 | ||||
-rw-r--r-- | os/utils.c | 12 |
3 files changed, 309 insertions, 1051 deletions
diff --git a/Xext/security.c b/Xext/security.c index ec414a0c3..6aab3a342 100644 --- a/Xext/security.c +++ b/Xext/security.c @@ -31,53 +31,47 @@ in this Software without prior written authorization from The Open Group. #include "scrnintstr.h" #include "colormapst.h" #include "privates.h" +#include "registry.h" #include "xacestr.h" #include "securitysrv.h" #include <X11/extensions/securstr.h> -#include <assert.h> -#include <stdarg.h> #ifdef XAPPGROUP #include "appgroup.h" #endif -#include <stdio.h> /* for file reading operations */ -#include <X11/Xatom.h> /* for XA_STRING */ - -#ifndef DEFAULTPOLICYFILE -# define DEFAULTPOLICYFILE NULL -#endif -#if defined(WIN32) || defined(__CYGWIN__) -#include <X11/Xos.h> -#undef index -#endif - #include "modinit.h" +/* Extension stuff */ static int SecurityErrorBase; /* first Security error number */ static int SecurityEventBase; /* first Security event number */ -static const DevPrivateKey stateKey = &stateKey; -/* this is what we store as client security state */ +RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */ +static RESTYPE RTEventClient; + +static CallbackListPtr SecurityValidateGroupCallback = NULL; + +/* Private state record */ +static DevPrivateKey stateKey = &stateKey; + +/* This is what we store as client security state */ typedef struct { int haveState; unsigned int trustLevel; XID authId; -} SecurityClientStateRec; - -#define HAVESTATE(client) (((SecurityClientStateRec *) \ - dixLookupPrivate(DEVPRIV_PTR(client), stateKey))->haveState) -#define TRUSTLEVEL(client) (((SecurityClientStateRec *) \ - dixLookupPrivate(DEVPRIV_PTR(client), stateKey))->trustLevel) -#define AUTHID(client)(((SecurityClientStateRec *) \ - dixLookupPrivate(DEVPRIV_PTR(client), stateKey))->authId) - -static CallbackListPtr SecurityValidateGroupCallback = NULL; - -static char **SecurityTrustedExtensions = NULL; -static int nSecurityTrustedExtensions = 0; +} SecurityStateRec; + +/* Extensions that untrusted clients shouldn't have access to */ +static char *SecurityUntrustedExtensions[] = { + "RandR", + "SECURITY", + "XFree86-DGA", + NULL +}; -RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */ +/* Access modes that untrusted clients can do to trusted stuff */ +static const Mask SecurityAllowedMask = + DixGetAttrAccess | DixListPropAccess | DixGetPropAccess | + DixGetFocusAccess | DixListAccess | DixReceiveAccess; -static RESTYPE RTEventClient; /* SecurityAudit * @@ -103,6 +97,51 @@ SecurityAudit(char *format, ...) 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); +} + + #define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) /* SecurityDeleteAuthorization @@ -163,10 +202,12 @@ SecurityDeleteAuthorization( /* kill all clients using this auth */ for (i = 1; i<currentMaxClients; i++) - { - if (clients[i] && (AUTHID(clients[i]) == pAuth->id)) - CloseDownClient(clients[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); xfree(pAuth); @@ -315,12 +356,6 @@ ProcSecurityQueryVersion( /* REQUEST(xSecurityQueryVersionReq); */ xSecurityQueryVersionReply rep; - /* paranoia: this "can't happen" because this extension is hidden - * from untrusted clients, but just in case... - */ - if (TRUSTLEVEL(client) != XSecurityClientTrusted) - return BadRequest; - REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); rep.type = X_Reply; rep.sequenceNumber = client->sequence; @@ -401,12 +436,6 @@ ProcSecurityGenerateAuthorization( char *pAuthdata; /* generated auth data */ Mask eventMask; /* what events on this auth does client want */ - /* paranoia: this "can't happen" because this extension is hidden - * from untrusted clients, but just in case... - */ - if (TRUSTLEVEL(client) != XSecurityClientTrusted) - return BadRequest; - /* check request length */ REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); @@ -584,12 +613,6 @@ ProcSecurityRevokeAuthorization( REQUEST(xSecurityRevokeAuthorizationReq); SecurityAuthorizationPtr pAuth; - /* paranoia: this "can't happen" because this extension is hidden - * from untrusted clients, but just in case... - */ - if (TRUSTLEVEL(client) != XSecurityClientTrusted) - return BadRequest; - REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); pAuth = (SecurityAuthorizationPtr)SecurityLookupIDByType(client, @@ -703,59 +726,6 @@ SwapSecurityAuthorizationRevokedEvent( cpswapl(from->authId, to->authId); } -/* SecurityDetermineEventPropogationLimits - * - * This is a helper function for SecurityCheckDeviceAccess. - * - * Arguments: - * dev is the device for which the starting and stopping windows for - * event propogation should be determined. - * The values pointed to by ppWin and ppStopWin are not used. - * - * Returns: - * ppWin is filled in with a pointer to the window at which event - * propogation for the given device should start given the current - * state of the server (pointer position, window layout, etc.) - * ppStopWin is filled in with the window at which event propogation - * should stop; events should not go to ppStopWin. - * - * Side Effects: none. - */ - -static void -SecurityDetermineEventPropogationLimits( - DeviceIntPtr dev, - WindowPtr *ppWin, - WindowPtr *ppStopWin) -{ - WindowPtr pFocusWin = dev->focus ? dev->focus->win : NoneWin; - - if (pFocusWin == NoneWin) - { /* no focus -- events don't go anywhere */ - *ppWin = *ppStopWin = NULL; - return; - } - - if (pFocusWin == PointerRootWin) - { /* focus follows the pointer */ - *ppWin = GetSpriteWindow(); - *ppStopWin = NULL; /* propogate all the way to the root */ - } - else - { /* a real window is set for the focus */ - WindowPtr pSpriteWin = GetSpriteWindow(); - *ppStopWin = pFocusWin->parent; /* don't go past the focus window */ - - /* if the pointer is in a subwindow of the focus window, start - * at that subwindow, else start at the focus window itself - */ - if (IsParent(pFocusWin, pSpriteWin)) - *ppWin = pSpriteWin; - else *ppWin = pFocusWin; - } -} /* SecurityDetermineEventPropogationLimits */ - - /* SecurityCheckDeviceAccess * * Arguments: @@ -773,163 +743,25 @@ SecurityDetermineEventPropogationLimits( */ static void -SecurityCheckDeviceAccess(CallbackListPtr *pcbl, pointer unused, - pointer calldata) +SecurityDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - XaceDeviceAccessRec *rec = (XaceDeviceAccessRec*)calldata; - ClientPtr client = rec->client; - DeviceIntPtr dev = rec->dev; - Bool fromRequest = rec->fromRequest; - WindowPtr pWin, pStopWin; - Bool untrusted_got_event; - Bool found_event_window; - Mask eventmask; - int reqtype = 0; - - /* trusted clients always allowed to do anything */ - if (TRUSTLEVEL(client) == XSecurityClientTrusted) - return; - - /* device security other than keyboard is not implemented yet */ - if (dev != inputInfo.keyboard) - return; - - /* some untrusted client wants access */ - - if (fromRequest) - { - reqtype = ((xReq *)client->requestBuffer)->reqType; - switch (reqtype) - { - /* never allow these */ - case X_ChangeKeyboardMapping: - case X_ChangeKeyboardControl: - case X_SetModifierMapping: - SecurityAudit("client %d attempted request %d\n", - client->index, reqtype); - rec->status = BadAccess; - return; - default: - break; - } - } - - untrusted_got_event = FALSE; - found_event_window = FALSE; - - if (dev->grab) - { - untrusted_got_event = - (TRUSTLEVEL(rClient(dev->grab)) != XSecurityClientTrusted); - } - else - { - SecurityDetermineEventPropogationLimits(dev, &pWin, &pStopWin); - - eventmask = KeyPressMask | KeyReleaseMask; - while ( (pWin != pStopWin) && !found_event_window) - { - OtherClients *other; - - if (pWin->eventMask & eventmask) - { - found_event_window = TRUE; - client = wClient(pWin); - if (TRUSTLEVEL(client) != XSecurityClientTrusted) - { - untrusted_got_event = TRUE; - } - } - if (wOtherEventMasks(pWin) & eventmask) - { - found_event_window = TRUE; - for (other = wOtherClients(pWin); other; other = other->next) - { - if (other->mask & eventmask) - { - client = rClient(other); - if (TRUSTLEVEL(client) != XSecurityClientTrusted) - { - untrusted_got_event = TRUE; - break; - } - } - } - } - if (wDontPropagateMask(pWin) & eventmask) - break; - pWin = pWin->parent; - } /* while propogating the event */ - } - - /* allow access by untrusted clients only if an event would have gone - * to an untrusted client - */ - - if (!untrusted_got_event) - { - char *devname = dev->name; - if (!devname) devname = "unnamed"; - if (fromRequest) - SecurityAudit("client %d attempted request %d device %d (%s)\n", - client->index, reqtype, dev->id, devname); - else - SecurityAudit("client %d attempted to access device %d (%s)\n", - client->index, dev->id, devname); + XaceDeviceAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityAllowedMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&serverClient->devPrivates, stateKey); + + 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; } - return; -} /* SecurityCheckDeviceAccess */ - - - -/* SecurityAuditResourceIDAccess - * - * Arguments: - * client is the client doing the resource access. - * id is the resource id. - * - * Returns: NULL - * - * Side Effects: - * An audit message is generated with details of the denied - * resource access. - */ - -static pointer -SecurityAuditResourceIDAccess( - ClientPtr client, - XID id) -{ - int cid = CLIENT_ID(id); - int reqtype = ((xReq *)client->requestBuffer)->reqType; - switch (reqtype) - { - case X_ChangeProperty: - case X_DeleteProperty: - case X_GetProperty: - { - xChangePropertyReq *req = - (xChangePropertyReq *)client->requestBuffer; - int propertyatom = req->property; - char *propertyname = NameForAtom(propertyatom); - - SecurityAudit("client %d attempted request %d with window 0x%x property %s of client %d\n", - client->index, reqtype, id, propertyname, cid); - break; - } - default: - { - SecurityAudit("client %d attempted request %d with resource 0x%x of client %d\n", - client->index, reqtype, id, cid); - break; - } - } - return NULL; -} /* SecurityAuditResourceIDAccess */ - +} -/* SecurityCheckResourceIDAccess +/* SecurityResource * * This function gets plugged into client->CheckAccess and is called from * SecurityLookupIDByType/Class to determine if the client can access the @@ -951,803 +783,245 @@ SecurityAuditResourceIDAccess( */ static void -SecurityCheckResourceIDAccess(CallbackListPtr *pcbl, pointer unused, - pointer calldata) +SecurityResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - XaceResourceAccessRec *rec = (XaceResourceAccessRec*)calldata; - ClientPtr client = rec->client; - XID id = rec->id; - RESTYPE rtype = rec->rtype; - Mask access_mode = rec->access_mode; - pointer rval = rec->res; - int cid, reqtype; - - if (TRUSTLEVEL(client) == XSecurityClientTrusted || - DixUnknownAccess == access_mode) - return; /* for compatibility, we have to allow access */ - - cid = CLIENT_ID(id); - reqtype = ((xReq *)client->requestBuffer)->reqType; - switch (reqtype) - { /* these are always allowed */ - case X_QueryTree: - case X_TranslateCoords: - case X_GetGeometry: - /* property access is controlled in SecurityCheckPropertyAccess */ - case X_GetProperty: - case X_ChangeProperty: - case X_DeleteProperty: - case X_RotateProperties: - case X_ListProperties: - return; - default: - break; + XaceResourceAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + int cid = CLIENT_ID(rec->id); + Mask requested = rec->access_mode; + Mask allowed = SecurityAllowedMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&clients[cid]->devPrivates, stateKey); + + /* special checks for server-owned resources */ + if (cid == 0) { + if (rec->rtype & RC_DRAWABLE) + /* additional operations allowed on root windows */ + allowed |= DixReadAccess|DixSendAccess; + + else if (rec->rtype == RT_COLORMAP) + /* allow access to default colormaps */ + allowed = requested; } - if (cid != 0) - { /* not a server-owned resource */ - /* - * The following 'if' restricts clients to only access resources at - * the same trustLevel. Since there are currently only two trust levels, - * and trusted clients never call this function, this degenerates into - * saying that untrusted clients can only access resources of other - * untrusted clients. One way to add the notion of groups would be to - * allow values other than Trusted (0) and Untrusted (1) for this field. - * Clients at the same trust level would be able to use each other's - * resources, but not those of clients at other trust levels. I haven't - * tried it, but this probably mostly works already. The obvious - * competing alternative for grouping clients for security purposes is to - * use app groups. dpw - */ - if (TRUSTLEVEL(client) == TRUSTLEVEL(clients[cid]) + if (SecurityDoCheck(subj, obj, requested, allowed) == Success) + return; + #ifdef XAPPGROUP - || (RT_COLORMAP == rtype && - XagDefaultColormap (client) == (Colormap) id) + if (rec->id == XagDefaultColormap(rec->client)) + return; #endif - ) - return; - else - goto deny; - } - else /* server-owned resource - probably a default colormap or root window */ - { - if (RT_WINDOW == rtype || RC_DRAWABLE == rtype) - { - switch (reqtype) - { /* the following operations are allowed on root windows */ - case X_CreatePixmap: - case X_CreateGC: - case X_CreateWindow: - case X_CreateColormap: - case X_ListProperties: - case X_GrabPointer: - case X_UngrabButton: - case X_QueryBestSize: - case X_GetWindowAttributes: - break; - case X_SendEvent: - { /* see if it is an event specified by the ICCCM */ - xSendEventReq *req = (xSendEventReq *) - (client->requestBuffer); - if (req->propagate == xTrue - || - (req->eventMask != ColormapChangeMask && - req->eventMask != StructureNotifyMask && - req->eventMask != - (SubstructureRedirectMask|SubstructureNotifyMask) - ) - || - (req->event.u.u.type != UnmapNotify && - req->event.u.u.type != ConfigureRequest && - req->event.u.u.type != ClientMessage - ) - ) - { /* not an ICCCM event */ - goto deny; - } - break; - } /* case X_SendEvent on root */ - - case X_ChangeWindowAttributes: - { /* Allow selection of PropertyNotify and StructureNotify - * events on the root. - */ - xChangeWindowAttributesReq *req = - (xChangeWindowAttributesReq *)(client->requestBuffer); - if (req->valueMask == CWEventMask) - { - CARD32 value = *((CARD32 *)(req + 1)); - if ( (value & - ~(PropertyChangeMask|StructureNotifyMask)) == 0) - break; - } - goto deny; - } /* case X_ChangeWindowAttributes on root */ - - default: - { - /* others not allowed */ - goto deny; - } - } - } /* end server-owned window or drawable */ - else if (SecurityAuthorizationResType == rtype) - { - SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)rval; - if (pAuth->trustLevel != TRUSTLEVEL(client)) - goto deny; - } - else if (RT_COLORMAP != rtype) - { /* don't allow anything else besides colormaps */ - goto deny; - } - } - return; - deny: - SecurityAuditResourceIDAccess(client, id); - rec->status = BadAccess; /* deny access */ -} /* SecurityCheckResourceIDAccess */ + SecurityAudit("Security: denied client %d access to resource 0x%x " + "of client %d on request %s\n", rec->client->index, rec->id, + cid, SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; /* deny access */ +} -/* 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 -SecurityClientStateCallback(CallbackListPtr *pcbl, pointer unused, - pointer calldata) +SecurityExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - NewClientInfoRec *pci = (NewClientInfoRec *)calldata; - ClientPtr client = pci->client; - - switch (client->clientState) - { - case ClientStateInitial: - TRUSTLEVEL(client) = XSecurityClientTrusted; - AUTHID(client) = None; - break; - - case ClientStateRunning: - { - XID authId = AuthorizationIDOfClient(client); - SecurityAuthorizationPtr pAuth; - - TRUSTLEVEL(client) = XSecurityClientTrusted; - AUTHID(client) = authId; - pAuth = (SecurityAuthorizationPtr)LookupIDByType(authId, - SecurityAuthorizationResType); - if (pAuth) - { /* it is a generated authorization */ - pAuth->refcnt++; - if (pAuth->refcnt == 1) - { - if (pAuth->timer) TimerCancel(pAuth->timer); - } - TRUSTLEVEL(client) = pAuth->trustLevel; + XaceExtAccessRec *rec = calldata; + SecurityStateRec *subj; + int i = 0; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + + if (subj->haveState && subj->trustLevel != XSecurityClientTrusted) + while (SecurityUntrustedExtensions[i]) + if (!strcmp(SecurityUntrustedExtensions[i++], rec->ext->name)) { + 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; + return; } - break; - } - case ClientStateGone: - case ClientStateRetained: /* client disconnected */ - { - SecurityAuthorizationPtr pAuth; - - /* client may not have any state (bad authorization) */ - if (!HAVESTATE(client)) - break; - - pAuth = (SecurityAuthorizationPtr)LookupIDByType(AUTHID(client), - SecurityAuthorizationResType); - if (pAuth) - { /* it is a generated authorization */ - pAuth->refcnt--; - if (pAuth->refcnt == 0) - { - SecurityStartAuthorizationTimer(pAuth); - } - } - break; - } - default: break; - } -} /* SecurityClientStateCallback */ - -static void -SecurityCheckDrawableAccess(CallbackListPtr *pcbl, pointer unused, - pointer calldata) -{ - XaceDrawableAccessRec *rec = (XaceDrawableAccessRec*)calldata; - - if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) - rec->status = BadAccess; } static void -SecurityCheckMapAccess(CallbackListPtr *pcbl, pointer unused, - pointer calldata) +SecurityServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata; - WindowPtr pWin = rec->pWin; - - if (HAVESTATE(rec->client) && - (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) && - (pWin->drawable.class == InputOnly) && - pWin->parent && pWin->parent->parent && - (TRUSTLEVEL(wClient(pWin->parent)) == XSecurityClientTrusted)) + XaceServerAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityAllowedMask; + 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 -SecurityCheckExtAccess(CallbackListPtr *pcbl, pointer unused, - pointer calldata) +SecurityClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - XaceExtAccessRec *rec = (XaceExtAccessRec*)calldata; - int i, trusted = 0; - - for (i = 0; i < nSecurityTrustedExtensions; i++) - if (!strcmp(SecurityTrustedExtensions[i], rec->ext->name)) - trusted = 1; - - if ((TRUSTLEVEL(rec->client) != XSecurityClientTrusted) && !trusted) + XaceClientAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityAllowedMask; + + 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 -SecurityCheckServerAccess(CallbackListPtr *pcbl, pointer unused, - pointer calldata) -{ - XaceServerAccessRec *rec = (XaceServerAccessRec*)calldata; - - if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) - { +SecurityProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XacePropertyAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + ATOM name = rec->pProp->propertyName; + Mask requested = rec->access_mode; + Mask allowed = SecurityAllowedMask | 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; - if (rec->access_mode == DixWriteAccess) - SecurityAudit("client %d attempted to change host access\n", - rec->client->index); - else - SecurityAudit("client %d attempted to list hosts\n", - rec->client->index); } } -/**********************************************************************/ - -typedef struct _PropertyAccessRec { - ATOM name; - ATOM mustHaveProperty; - char *mustHaveValue; - char windowRestriction; -#define SecurityAnyWindow 0 -#define SecurityRootWindow 1 -#define SecurityWindowWithProperty 2 - int readAction; - int writeAction; - int destroyAction; - struct _PropertyAccessRec *next; -} PropertyAccessRec, *PropertyAccessPtr; - -static PropertyAccessPtr PropertyAccessList = NULL; -static int SecurityDefaultAction = BadAtom; -static char *SecurityPolicyFile = DEFAULTPOLICYFILE; -static ATOM SecurityMaxPropertyName = 0; - -static char *SecurityKeywords[] = { -#define SecurityKeywordComment 0 - "#", -#define SecurityKeywordProperty 1 - "property", -#define SecurityKeywordSitePolicy 2 - "sitepolicy", -#define SecurityKeywordRoot 3 - "root", -#define SecurityKeywordAny 4 - "any", -#define SecurityKeywordExtension 5 - "trust extension", -}; - -#define NUMKEYWORDS (sizeof(SecurityKeywords) / sizeof(char *)) - static void -SecurityFreePropertyAccessList(void) +SecuritySend(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - while (PropertyAccessList) - { - PropertyAccessPtr freeit = PropertyAccessList; - PropertyAccessList = PropertyAccessList->next; - xfree(freeit); - } -} /* SecurityFreePropertyAccessList */ + XaceSendAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; -#define SecurityIsWhitespace(c) ( (c == ' ') || (c == '\t') || (c == '\n') ) - -static char * -SecuritySkipWhitespace( - char *p) -{ - while (SecurityIsWhitespace(*p)) - p++; - return p; -} /* SecuritySkipWhitespace */ - - -static char * -SecurityParseString( - char **rest) -{ - char *startOfString; - char *s = *rest; - char endChar = 0; - - s = SecuritySkipWhitespace(s); - - if (*s == '"' || *s == '\'') - { - endChar = *s++; - startOfString = s; - while (*s && (*s != endChar)) - s++; - } - else - { - startOfString = s; - while (*s && !SecurityIsWhitespace(*s)) - s++; - } - if (*s) - { - *s = '\0'; - *rest = s + 1; - return startOfString; - } - else - { - *rest = s; - return (endChar) ? NULL : startOfString; - } -} /* SecurityParseString */ - - -static int -SecurityParseKeyword( - char **p) -{ - int i; - char *s = *p; - s = SecuritySkipWhitespace(s); - for (i = 0; i < NUMKEYWORDS; i++) - { - int len = strlen(SecurityKeywords[i]); - if (strncmp(s, SecurityKeywords[i], len) == 0) - { - *p = s + len; - return (i); - } - } - *p = s; - return -1; -} /* SecurityParseKeyword */ + if (rec->client) { + int i; + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); -static Bool -SecurityParsePropertyAccessRule( - char *p) -{ - char *propname; - char c; - int action = SecurityDefaultAction; - int readAction, writeAction, destroyAction; - PropertyAccessPtr pacl, prev, cur; - char *mustHaveProperty = NULL; - char *mustHaveValue = NULL; - Bool invalid; - char windowRestriction; - int size; - int keyword; - - /* get property name */ - propname = SecurityParseString(&p); - if (!propname || (strlen(propname) == 0)) - return FALSE; - - /* get window on which property must reside for rule to apply */ - - keyword = SecurityParseKeyword(&p); - if (keyword == SecurityKeywordRoot) - windowRestriction = SecurityRootWindow; - else if (keyword == SecurityKeywordAny) - windowRestriction = SecurityAnyWindow; - else /* not root or any, must be a property name */ - { - mustHaveProperty = SecurityParseString(&p); - if (!mustHaveProperty || (strlen(mustHaveProperty) == 0)) - return FALSE; - windowRestriction = SecurityWindowWithProperty; - p = SecuritySkipWhitespace(p); - if (*p == '=') - { /* property value is specified too */ - p++; /* skip over '=' */ - mustHaveValue = SecurityParseString(&p); - if (!mustHaveValue) - return FALSE; - } - } - - /* get operations and actions */ - - invalid = FALSE; - readAction = writeAction = destroyAction = SecurityDefaultAction; - while ( (c = *p++) && !invalid) - { - switch (c) - { - case 'i': action = XaceIgnoreError; break; - case 'a': action = Success; break; - case 'e': action = BadAtom; break; - - case 'r': readAction = action; break; - case 'w': writeAction = action; break; - case 'd': destroyAction = action; break; - - default : - if (!SecurityIsWhitespace(c)) - invalid = TRUE; - break; - } - } - if (invalid) - return FALSE; - - /* We've successfully collected all the information needed for this - * property access rule. Now record it in a PropertyAccessRec. - */ - size = sizeof(PropertyAccessRec); - - /* If there is a property value string, allocate space for it - * right after the PropertyAccessRec. - */ - if (mustHaveValue) - size += strlen(mustHaveValue) + 1; - pacl = (PropertyAccessPtr)Xalloc(size); - if (!pacl) - return FALSE; - - pacl->name = MakeAtom(propname, strlen(propname), TRUE); - if (pacl->name == BAD_RESOURCE) - { - Xfree(pacl); - return FALSE; - } - if (mustHaveProperty) - { - pacl->mustHaveProperty = MakeAtom(mustHaveProperty, - strlen(mustHaveProperty), TRUE); - if (pacl->mustHaveProperty == BAD_RESOURCE) - { - Xfree(pacl); - return FALSE; - } - } - else - pacl->mustHaveProperty = 0; - - if (mustHaveValue) - { - pacl->mustHaveValue = (char *)(pacl + 1); - strcpy(pacl->mustHaveValue, mustHaveValue); - } - else - pacl->mustHaveValue = NULL; - - SecurityMaxPropertyName = max(SecurityMaxPropertyName, pacl->name); - - pacl->windowRestriction = windowRestriction; - pacl->readAction = readAction; - pacl->writeAction = writeAction; - pacl->destroyAction = destroyAction; + if (SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success) + return; - /* link the new rule into the list of rules in order of increasing - * property name (atom) value to make searching easier - */ + 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) { - for (prev = NULL, cur = PropertyAccessList; - cur && cur->name <= pacl->name; - prev = cur, cur = cur->next) - ; - if (!prev) - { - pacl->next = cur; - PropertyAccessList = pacl; - } - else - { - prev->next = pacl; - pacl->next = cur; + SecurityAudit("Security: denied client %d from sending event " + "of type %s to window 0x%x of client %d\n", + rec->client->index, rec->pWin->drawable.id, + wClient(rec->pWin)->index, + LookupEventName(rec->events[i].u.u.type)); + rec->status = BadAccess; + return; + } } - return TRUE; -} /* SecurityParsePropertyAccessRule */ +} -static Bool -SecurityParseExtensionRule( - char *p) +static void +SecurityReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - char *extName = SecurityParseString(&p); - char *copyExtName; - char **newStrings; - - if (!extName) - return FALSE; - - copyExtName = (char *)Xalloc(strlen(extName) + 1); - if (!copyExtName) - return TRUE; - strcpy(copyExtName, extName); - newStrings = (char **)Xrealloc(SecurityTrustedExtensions, - sizeof (char *) * (nSecurityTrustedExtensions + 1)); - if (!newStrings) - { - Xfree(copyExtName); - return TRUE; - } + XaceReceiveAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; - SecurityTrustedExtensions = newStrings; - SecurityTrustedExtensions[nSecurityTrustedExtensions++] = copyExtName; + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); - return TRUE; + if (SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success) + return; -} /* SecurityParseExtensionRule */ + 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; +} -static void -SecurityFreeTrustedExtensionStrings(void) -{ - if (SecurityTrustedExtensions) - { - assert(nSecurityTrustedExtensions); - while (nSecurityTrustedExtensions--) - { - Xfree(SecurityTrustedExtensions[nSecurityTrustedExtensions]); - } - Xfree(SecurityTrustedExtensions); - SecurityTrustedExtensions = NULL; - nSecurityTrustedExtensions = 0; - } -} /* SecurityFreeSiteTrustedExtensions */ +/* 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 -SecurityLoadPropertyAccessList(void) +SecurityClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) { - FILE *f; - int lineNumber = 0; - - SecurityMaxPropertyName = 0; - - if (!SecurityPolicyFile) - return; - - f = fopen(SecurityPolicyFile, "r"); - if (!f) - { - ErrorF("error opening security policy file %s\n", - SecurityPolicyFile); - return; - } + NewClientInfoRec *pci = calldata; + SecurityStateRec *state; + SecurityAuthorizationPtr pAuth; + int rc; - while (!feof(f)) - { - char buf[200]; - Bool validLine; - char *p; + state = dixLookupPrivate(&pci->client->devPrivates, stateKey); - if (!(p = fgets(buf, sizeof(buf), f))) - break; - lineNumber++; + switch (pci->client->clientState) { + case ClientStateInitial: + state->trustLevel = XSecurityClientTrusted; + state->authId = None; + state->haveState = TRUE; + break; - /* if first line, check version number */ - if (lineNumber == 1) - { - char *v = SecurityParseString(&p); - if (strcmp(v, SECURITY_POLICY_FILE_VERSION) != 0) - { - ErrorF("%s: invalid security policy file version, ignoring file\n", - SecurityPolicyFile); - break; - } - validLine = TRUE; - } - else - { - switch (SecurityParseKeyword(&p)) - { - case SecurityKeywordComment: - case SecurityKeywordSitePolicy: - validLine = TRUE; - break; - - case SecurityKeywordProperty: - validLine = SecurityParsePropertyAccessRule(p); - break; - - case SecurityKeywordExtension: - validLine = SecurityParseExtensionRule(p); - break; - - default: - validLine = (*p == '\0'); /* blank lines OK, others not */ - break; - } + case ClientStateRunning: + state->authId = AuthorizationIDOfClient(pci->client); + rc = dixLookupResource((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; - if (!validLine) - ErrorF("Line %d of %s invalid, ignoring\n", - lineNumber, SecurityPolicyFile); - } /* end while more input */ - - fclose(f); -} /* SecurityLoadPropertyAccessList */ - - -static Bool -SecurityMatchString( - char *ws, - char *cs) -{ - while (*ws && *cs) - { - if (*ws == '*') - { - Bool match = FALSE; - ws++; - while (!(match = SecurityMatchString(ws, cs)) && *cs) - { - cs++; - } - return match; - } - else if (*ws == *cs) - { - ws++; - cs++; + case ClientStateGone: + case ClientStateRetained: + rc = dixLookupResource((pointer *)&pAuth, state->authId, + SecurityAuthorizationResType, serverClient, + DixGetAttrAccess); + if (rc == Success) { + /* it is a generated authorization */ + pAuth->refcnt--; + if (pAuth->refcnt == 0) + SecurityStartAuthorizationTimer(pAuth); } - else break; - } - return ( ( (*ws == '\0') || ((*ws == '*') && *(ws+1) == '\0') ) - && (*cs == '\0') ); -} /* SecurityMatchString */ - - -static void -SecurityCheckPropertyAccess(CallbackListPtr *pcbl, pointer unused, - pointer calldata) -{ - XacePropertyAccessRec *rec = (XacePropertyAccessRec*)calldata; - ClientPtr client = rec->client; - WindowPtr pWin = rec->pWin; - ATOM propertyName = rec->pProp->propertyName; - Mask access_mode = rec->access_mode; - PropertyAccessPtr pacl; - int action = SecurityDefaultAction; - - /* if client trusted or window untrusted, allow operation */ - - if ((TRUSTLEVEL(client) == XSecurityClientTrusted) || - (TRUSTLEVEL(wClient(pWin)) != XSecurityClientTrusted) ) - return; - - /* If the property atom is bigger than any atoms on the list, - * we know we won't find it, so don't even bother looking. - */ - if (propertyName <= SecurityMaxPropertyName) - { - /* untrusted client operating on trusted window; see if it's allowed */ - - for (pacl = PropertyAccessList; pacl; pacl = pacl->next) - { - if (pacl->name < propertyName) - continue; - if (pacl->name > propertyName) - break; - - /* pacl->name == propertyName, so see if it applies to this window */ + break; - switch (pacl->windowRestriction) - { - case SecurityAnyWindow: /* always applies */ - break; - - case SecurityRootWindow: - { - /* if not a root window, this rule doesn't apply */ - if (pWin->parent) - continue; - } - break; - - case SecurityWindowWithProperty: - { - PropertyPtr pProp = wUserProps (pWin); - Bool match = FALSE; - char *p; - char *pEndData; - - while (pProp) - { - if (pProp->propertyName == pacl->mustHaveProperty) - break; - pProp = pProp->next; - } - if (!pProp) - continue; - if (!pacl->mustHaveValue) - break; - if (pProp->type != XA_STRING || pProp->format != 8) - continue; - - p = pProp->data; - pEndData = ((char *)pProp->data) + pProp->size; - while (!match && p < pEndData) - { - if (SecurityMatchString(pacl->mustHaveValue, p)) - match = TRUE; - else - { /* skip to the next string */ - while (*p++ && p < pEndData) - ; - } - } - if (!match) - continue; - } - break; /* end case SecurityWindowWithProperty */ - } /* end switch on windowRestriction */ - - /* If we get here, the property access rule pacl applies. - * If pacl doesn't apply, something above should have - * executed a continue, which will skip the follwing code. - */ - action = Success; - if (access_mode & DixReadAccess) - action = max(action, pacl->readAction); - if (access_mode & DixWriteAccess) - action = max(action, pacl->writeAction); - if (access_mode & DixDestroyAccess) - action = max(action, pacl->destroyAction); - break; - } /* end for each pacl */ - } /* end if propertyName <= SecurityMaxPropertyName */ - - if (action != Success) - { /* audit the access violation */ - int cid = CLIENT_ID(pWin->drawable.id); - int reqtype = ((xReq *)client->requestBuffer)->reqType; - char *actionstr = (XaceIgnoreError == action) ? "ignored" : "error"; - SecurityAudit("client %d attempted request %d with window 0x%x property %s (atom 0x%x) of client %d, %s\n", - client->index, reqtype, pWin->drawable.id, - NameForAtom(propertyName), propertyName, cid, actionstr); + default: + break; } - /* return codes increase with strictness */ - if (action != Success) - rec->status = action; -} /* SecurityCheckPropertyAccess */ - +} /* SecurityResetProc * @@ -1764,25 +1038,19 @@ static void SecurityResetProc( ExtensionEntry *extEntry) { - SecurityFreePropertyAccessList(); - SecurityFreeTrustedExtensionStrings(); -} /* SecurityResetProc */ - - -int -XSecurityOptions(argc, argv, i) - int argc; - char **argv; - int i; -{ - if (strcmp(argv[i], "-sp") == 0) - { - if (i < argc) - SecurityPolicyFile = argv[++i]; - return (i + 1); - } - return (i); -} /* XSecurityOptions */ + /* 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 @@ -1799,6 +1067,7 @@ void SecurityExtensionInit(INITARGS) { ExtensionEntry *extEntry; + int ret = TRUE; SecurityAuthorizationResType = CreateNewResourceType(SecurityDeleteAuthorization); @@ -1812,12 +1081,26 @@ SecurityExtensionInit(INITARGS) RTEventClient |= RC_NEVERRETAIN; /* Allocate the private storage */ - if (!dixRequestPrivate(stateKey, sizeof(SecurityClientStateRec))) + if (!dixRequestPrivate(stateKey, sizeof(SecurityStateRec))) FatalError("SecurityExtensionSetup: Can't allocate client private.\n"); - if (!AddCallback(&ClientStateCallback, SecurityClientStateCallback, NULL)) - return; + /* 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, @@ -1829,15 +1112,6 @@ SecurityExtensionInit(INITARGS) EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] = (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent; - SecurityLoadPropertyAccessList(); - - /* register callbacks */ -#define XaceRC XaceRegisterCallback - XaceRC(XACE_RESOURCE_ACCESS, SecurityCheckResourceIDAccess, NULL); - XaceRC(XACE_DEVICE_ACCESS, SecurityCheckDeviceAccess, NULL); - XaceRC(XACE_PROPERTY_ACCESS, SecurityCheckPropertyAccess, NULL); - XaceRC(XACE_MAP_ACCESS, SecurityCheckMapAccess, NULL); - XaceRC(XACE_EXT_DISPATCH, SecurityCheckExtAccess, NULL); - XaceRC(XACE_EXT_ACCESS, SecurityCheckExtAccess, NULL); - XaceRC(XACE_SERVER_ACCESS, SecurityCheckServerAccess, NULL); -} /* SecurityExtensionInit */ + /* Label objects that were created before we could register ourself */ + SecurityLabelInitial(); +} diff --git a/Xext/securitysrv.h b/Xext/securitysrv.h index 7320ab7da..f4f3e32ae 100644 --- a/Xext/securitysrv.h +++ b/Xext/securitysrv.h @@ -77,11 +77,7 @@ typedef struct { Bool valid; /* did anyone recognize it? if so, set to TRUE */ } SecurityValidateGroupInfoRec; -extern int XSecurityOptions(int argc, char **argv, int i); - /* Give this value or higher to the -audit option to get security messages */ #define SECURITY_AUDIT_LEVEL 4 -#define SECURITY_POLICY_FILE_VERSION "version-1" - #endif /* _SECURITY_SRV_H */ diff --git a/os/utils.c b/os/utils.c index 322814669..d69936df7 100644 --- a/os/utils.c +++ b/os/utils.c @@ -123,9 +123,6 @@ OR PERFORMANCE OF THIS SOFTWARE. #ifdef XKB #include <xkbsrv.h> #endif -#ifdef XCSECURITY -#include "securitysrv.h" -#endif #ifdef RENDER #include "picture.h" @@ -621,9 +618,6 @@ void UseMsg(void) ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); #endif ErrorF("-s # screen-saver timeout (minutes)\n"); -#ifdef XCSECURITY - ErrorF("-sp file security policy file\n"); -#endif #ifdef XPRINT PrinterUseMsg(); #endif @@ -1040,12 +1034,6 @@ ProcessCommandLine(int argc, char *argv[]) i = skip - 1; } #endif -#ifdef XCSECURITY - else if ((skip = XSecurityOptions(argc, argv, i)) != i) - { - i = skip - 1; - } -#endif #ifdef AIXV3 else if ( strcmp( argv[i], "-timeout") == 0) { |