1097 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1097 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
| 
 | |
| 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.
 | |
| 
 | |
| */
 | |
| 
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #include <X11/Xmd.h>
 | |
| #include <X11/extensions/securproto.h>
 | |
| #include <X11/Xfuncproto.h>
 | |
| 
 | |
| #include "dix/dix_priv.h"
 | |
| #include "dix/registry_priv.h"
 | |
| #include "dix/resource_priv.h"
 | |
| #include "include/extinit_priv.h"
 | |
| #include "os/audit.h"
 | |
| #include "os/auth.h"
 | |
| #include "os/client_priv.h"
 | |
| #include "os/osdep.h"
 | |
| 
 | |
| #include "scrnintstr.h"
 | |
| #include "inputstr.h"
 | |
| #include "windowstr.h"
 | |
| #include "propertyst.h"
 | |
| #include "colormapst.h"
 | |
| #include "privates.h"
 | |
| #include "xacestr.h"
 | |
| #include "securitysrv.h"
 | |
| #include "extinit.h"
 | |
| #include "protocol-versions.h"
 | |
| 
 | |
| Bool noSecurityExtension = FALSE;
 | |
| 
 | |
| /* 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 {
 | |
|     unsigned int haveState  :1;
 | |
|     unsigned int live       :1;
 | |
|     unsigned int trustLevel :2;
 | |
|     XID authId;
 | |
| } SecurityStateRec;
 | |
| 
 | |
| /* The only extensions that untrusted clients have access to */
 | |
| static const char *SecurityTrustedExtensions[] = {
 | |
|     "XC-MISC",
 | |
|     "BIG-REQUESTS",
 | |
|     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
 | |
| _X_ATTRIBUTE_PRINTF(1, 2)
 | |
| SecurityAudit(const 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;
 | |
|     state->live = FALSE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Looks up a request name
 | |
|  */
 | |
| static inline const char *
 | |
| SecurityLookupRequestName(ClientPtr client)
 | |
| {
 | |
|     return LookupRequestName(client->majorOp, client->minorOp);
 | |
| }
 | |
| 
 | |
| /* 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(void *value, XID id)
 | |
| {
 | |
|     SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr) value;
 | |
|     unsigned short name_len, data_len;
 | |
|     const char *name;
 | |
|     char *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 = {
 | |
|             .type = SecurityEventBase + XSecurityAuthorizationRevoked,
 | |
|             .authId = pAuth->id
 | |
|         };
 | |
|         WriteEventsToClient(dixClientForOtherClients(pEventClient), 1, (xEvent *) &are);
 | |
|         FreeResource(pEventClient->resource, X11_RESTYPE_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 %lu\n", (unsigned long)pAuth->id);
 | |
|     free(pAuth);
 | |
|     return Success;
 | |
| 
 | |
| }                               /* SecurityDeleteAuthorization */
 | |
| 
 | |
| /* resource delete function for RTEventClient */
 | |
| static int
 | |
| SecurityDeleteAuthorizationEventClient(void *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, void *pval)
 | |
| {
 | |
|     SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr) pval;
 | |
| 
 | |
|     assert(pAuth->timer == timer);
 | |
| 
 | |
|     if (pAuth->secondsRemaining) {
 | |
|         return SecurityComputeAuthorizationTimeout(pAuth,
 | |
|                                                    pAuth->secondsRemaining);
 | |
|     }
 | |
|     else {
 | |
|         FreeResource(pAuth->id, X11_RESTYPE_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 = {
 | |
|         .type = X_Reply,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .length = 0,
 | |
|         .majorVersion = SERVER_SECURITY_MAJOR_VERSION,
 | |
|         .minorVersion = SERVER_SECURITY_MINOR_VERSION
 | |
|     };
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swaps(&rep.majorVersion);
 | |
|         swaps(&rep.minorVersion);
 | |
|     }
 | |
|     WriteToClient(client, SIZEOF(xSecurityQueryVersionReply), &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, X11_RESTYPE_NONE);
 | |
|             else
 | |
|                 pEventClient->mask = mask;
 | |
|             return Success;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pEventClient = calloc(1, sizeof(OtherClients));
 | |
|     if (!pEventClient)
 | |
|         return BadAlloc;
 | |
|     pEventClient->mask = mask;
 | |
|     pEventClient->resource = FakeClientID(client->index);
 | |
|     pEventClient->next = pAuth->eventClients;
 | |
|     if (!AddResource(pEventClient->resource, RTEventClient, (void *) 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? */
 | |
|     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, (void *) &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 (!authId) {
 | |
|         return SecurityErrorBase + XSecurityBadAuthorizationProtocol;
 | |
|     }
 | |
| 
 | |
|     /* 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 */
 | |
| 
 | |
|     SecurityAuthorizationPtr pAuth = calloc(1, 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 = (xSecurityGenerateAuthorizationReply) {
 | |
|         .type = X_Reply,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .length = bytes_to_int32(authdata_len),
 | |
|         .authId = authId,
 | |
|         .dataLength = authdata_len
 | |
|     };
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swapl(&rep.length);
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.authId);
 | |
|         swaps(&rep.dataLength);
 | |
|     }
 | |
| 
 | |
|     WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply), &rep);
 | |
|     WriteToClient(client, authdata_len, pAuthdata);
 | |
| 
 | |
|     SecurityAudit
 | |
|         ("client %d generated authorization %lu trust %d timeout %lu group %lu events %lu\n",
 | |
|          client->index, (unsigned long)pAuth->id, pAuth->trustLevel, (unsigned long)pAuth->timeout,
 | |
|          (unsigned long)pAuth->group, (unsigned long)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((void **) &pAuth, stuff->authId,
 | |
|                                  SecurityAuthorizationResType, client,
 | |
|                                  DixDestroyAccess);
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
| 
 | |
|     FreeResource(stuff->authId, X11_RESTYPE_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 _X_COLD
 | |
| SProcSecurityQueryVersion(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSecurityQueryVersionReq);
 | |
|     REQUEST_SIZE_MATCH(xSecurityQueryVersionReq);
 | |
|     swaps(&stuff->majorVersion);
 | |
|     swaps(&stuff->minorVersion);
 | |
|     return ProcSecurityQueryVersion(client);
 | |
| }                               /* SProcSecurityQueryVersion */
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSecurityGenerateAuthorization(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSecurityGenerateAuthorizationReq);
 | |
|     CARD32 *values;
 | |
|     unsigned long nvalues;
 | |
|     int values_offset;
 | |
|     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 >
 | |
|         client->req_len - bytes_to_int32(sz_xSecurityGenerateAuthorizationReq))
 | |
|         return BadLength;
 | |
|     values = (CARD32 *) (&stuff[1]) + values_offset;
 | |
|     nvalues = (((CARD32 *) stuff) + client->req_len) - values;
 | |
|     SwapLongs(values, nvalues);
 | |
|     return ProcSecurityGenerateAuthorization(client);
 | |
| }                               /* SProcSecurityGenerateAuthorization */
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSecurityRevokeAuthorization(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSecurityRevokeAuthorizationReq);
 | |
|     REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq);
 | |
|     swapl(&stuff->authId);
 | |
|     return ProcSecurityRevokeAuthorization(client);
 | |
| }                               /* SProcSecurityRevokeAuthorization */
 | |
| 
 | |
| static int _X_COLD
 | |
| 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 _X_COLD
 | |
| 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, void *unused, void *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, void *unused, void *calldata)
 | |
| {
 | |
|     XaceResourceAccessRec *rec = calldata;
 | |
|     SecurityStateRec *subj, *obj;
 | |
|     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 == X11_RESTYPE_WINDOW))
 | |
|         if (subj->haveState && subj->trustLevel != XSecurityClientTrusted)
 | |
|             ((WindowPtr) rec->res)->forcedBG = TRUE;
 | |
| 
 | |
|     /* additional permissions for specific resource types */
 | |
|     if (rec->rtype == X11_RESTYPE_WINDOW)
 | |
|         allowed |= SecurityWindowExtraMask;
 | |
| 
 | |
|     ClientPtr owner = dixClientForXID(rec->id);
 | |
|     if (!owner)
 | |
|         goto denied;
 | |
| 
 | |
|     /* special checks for server-owned resources */
 | |
|     if (owner == serverClient) {
 | |
|         if (rec->rtype & RC_DRAWABLE)
 | |
|             /* additional operations allowed on root windows */
 | |
|             allowed |= SecurityRootWindowExtraMask;
 | |
| 
 | |
|         else if (rec->rtype == X11_RESTYPE_COLORMAP)
 | |
|             /* allow access to default colormaps */
 | |
|             allowed = requested;
 | |
| 
 | |
|         else
 | |
|             /* allow read access to other server-owned resources */
 | |
|             allowed |= DixReadAccess;
 | |
|     }
 | |
| 
 | |
|     obj = dixLookupPrivate(&owner->devPrivates, stateKey);
 | |
|     if (SecurityDoCheck(subj, obj, requested, allowed) == Success)
 | |
|         return;
 | |
| 
 | |
| denied:
 | |
|     SecurityAudit("Security: denied client %d access %lx to resource 0x%lx "
 | |
|                   "of client %d on request %s\n", rec->client->index,
 | |
|                   (unsigned long)requested, (unsigned long)rec->id,
 | |
|                   dixClientIdForXID(rec->id),
 | |
|                   SecurityLookupRequestName(rec->client));
 | |
|     rec->status = BadAccess;    /* deny access */
 | |
| }
 | |
| 
 | |
| static void
 | |
| SecurityExtension(CallbackListPtr *pcbl, void *unused, void *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, void *unused, void *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, void *unused, void *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, void *unused, void *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(&dixClientForWindow(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%lx of client %d on request %s\n",
 | |
|                       rec->client->index, NameForAtom(name), name,
 | |
|                       (unsigned long)rec->pWin->drawable.id, dixClientForWindow(rec->pWin)->index,
 | |
|                       SecurityLookupRequestName(rec->client));
 | |
|         rec->status = BadAccess;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| SecuritySend(CallbackListPtr *pcbl, void *unused, void *calldata)
 | |
| {
 | |
|     XaceSendAccessRec *rec = calldata;
 | |
|     SecurityStateRec *subj, *obj;
 | |
| 
 | |
|     if (rec->client) {
 | |
|         int i;
 | |
| 
 | |
|         subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
 | |
|         obj = dixLookupPrivate(&dixClientForWindow(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%lx of client %d\n",
 | |
|                               rec->client->index,
 | |
|                               LookupEventName(rec->events[i].u.u.type),
 | |
|                               (unsigned long)rec->pWin->drawable.id,
 | |
|                               dixClientForWindow(rec->pWin)->index);
 | |
|                 rec->status = BadAccess;
 | |
|                 return;
 | |
|             }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| SecurityReceive(CallbackListPtr *pcbl, void *unused, void *calldata)
 | |
| {
 | |
|     XaceReceiveAccessRec *rec = calldata;
 | |
|     SecurityStateRec *subj, *obj;
 | |
| 
 | |
|     subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
 | |
|     obj = dixLookupPrivate(&dixClientForWindow(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%lx of client %d\n",
 | |
|                   rec->client->index, (unsigned long)rec->pWin->drawable.id,
 | |
|                   dixClientForWindow(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, void *unused, void *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;
 | |
|         state->live = FALSE;
 | |
|         break;
 | |
| 
 | |
|     case ClientStateRunning:
 | |
|         state->authId = AuthorizationIDOfClient(pci->client);
 | |
|         rc = dixLookupResourceByType((void **) &pAuth, state->authId,
 | |
|                                      SecurityAuthorizationResType, serverClient,
 | |
|                                      DixGetAttrAccess);
 | |
|         if (rc == Success) {
 | |
|             /* it is a generated authorization */
 | |
|             pAuth->refcnt++;
 | |
|             state->live = TRUE;
 | |
|             if (pAuth->refcnt == 1 && pAuth->timer)
 | |
|                 TimerCancel(pAuth->timer);
 | |
| 
 | |
|             state->trustLevel = pAuth->trustLevel;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|     case ClientStateGone:
 | |
|     case ClientStateRetained:
 | |
|         rc = dixLookupResourceByType((void **) &pAuth, state->authId,
 | |
|                                      SecurityAuthorizationResType, serverClient,
 | |
|                                      DixGetAttrAccess);
 | |
|         if (rc == Success && state->live) {
 | |
|             /* it is a generated authorization */
 | |
|             pAuth->refcnt--;
 | |
|             state->live = FALSE;
 | |
|             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(void)
 | |
| {
 | |
|     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();
 | |
| }
 |