xace.c revision 05b261ec
105b261ecSmrg/************************************************************ 205b261ecSmrg 305b261ecSmrgAuthor: Eamon Walsh <ewalsh@epoch.ncsc.mil> 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthis permission notice appear in supporting documentation. This permission 805b261ecSmrgnotice shall be included in all copies or substantial portions of the 905b261ecSmrgSoftware. 1005b261ecSmrg 1105b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1205b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1305b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1405b261ecSmrgAUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1505b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1605b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1705b261ecSmrg 1805b261ecSmrg********************************************************/ 1905b261ecSmrg 2005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 2105b261ecSmrg#include <dix-config.h> 2205b261ecSmrg#endif 2305b261ecSmrg 2405b261ecSmrg#include <stdarg.h> 2505b261ecSmrg#include "windowstr.h" 2605b261ecSmrg#include "scrnintstr.h" 2705b261ecSmrg#include "gcstruct.h" 2805b261ecSmrg#include "xacestr.h" 2905b261ecSmrg#include "modinit.h" 3005b261ecSmrg 3105b261ecSmrgCallbackListPtr XaceHooks[XACE_NUM_HOOKS] = {0}; 3205b261ecSmrg 3305b261ecSmrg/* Proc vectors for untrusted clients, swapped and unswapped versions. 3405b261ecSmrg * These are the same as the normal proc vectors except that extensions 3505b261ecSmrg * that haven't declared themselves secure will have ProcBadRequest plugged 3605b261ecSmrg * in for their major opcode dispatcher. This prevents untrusted clients 3705b261ecSmrg * from guessing extension major opcodes and using the extension even though 3805b261ecSmrg * the extension can't be listed or queried. 3905b261ecSmrg */ 4005b261ecSmrgstatic int (*UntrustedProcVector[256])( 4105b261ecSmrg ClientPtr /*client*/ 4205b261ecSmrg); 4305b261ecSmrgstatic int (*SwappedUntrustedProcVector[256])( 4405b261ecSmrg ClientPtr /*client*/ 4505b261ecSmrg); 4605b261ecSmrg 4705b261ecSmrg/* Entry point for hook functions. Called by Xserver. 4805b261ecSmrg */ 4905b261ecSmrgint XaceHook(int hook, ...) 5005b261ecSmrg{ 5105b261ecSmrg pointer calldata; /* data passed to callback */ 5205b261ecSmrg int *prv = NULL; /* points to return value from callback */ 5305b261ecSmrg va_list ap; /* argument list */ 5405b261ecSmrg va_start(ap, hook); 5505b261ecSmrg 5605b261ecSmrg /* Marshal arguments for passing to callback. 5705b261ecSmrg * Each callback has its own case, which sets up a structure to hold 5805b261ecSmrg * the arguments and integer return parameter, or in some cases just 5905b261ecSmrg * sets calldata directly to a single argument (with no return result) 6005b261ecSmrg */ 6105b261ecSmrg switch (hook) 6205b261ecSmrg { 6305b261ecSmrg case XACE_CORE_DISPATCH: { 6405b261ecSmrg XaceCoreDispatchRec rec = { 6505b261ecSmrg va_arg(ap, ClientPtr), 6605b261ecSmrg TRUE /* default allow */ 6705b261ecSmrg }; 6805b261ecSmrg calldata = &rec; 6905b261ecSmrg prv = &rec.rval; 7005b261ecSmrg break; 7105b261ecSmrg } 7205b261ecSmrg case XACE_RESOURCE_ACCESS: { 7305b261ecSmrg XaceResourceAccessRec rec = { 7405b261ecSmrg va_arg(ap, ClientPtr), 7505b261ecSmrg va_arg(ap, XID), 7605b261ecSmrg va_arg(ap, RESTYPE), 7705b261ecSmrg va_arg(ap, Mask), 7805b261ecSmrg va_arg(ap, pointer), 7905b261ecSmrg TRUE /* default allow */ 8005b261ecSmrg }; 8105b261ecSmrg calldata = &rec; 8205b261ecSmrg prv = &rec.rval; 8305b261ecSmrg break; 8405b261ecSmrg } 8505b261ecSmrg case XACE_DEVICE_ACCESS: { 8605b261ecSmrg XaceDeviceAccessRec rec = { 8705b261ecSmrg va_arg(ap, ClientPtr), 8805b261ecSmrg va_arg(ap, DeviceIntPtr), 8905b261ecSmrg va_arg(ap, Bool), 9005b261ecSmrg TRUE /* default allow */ 9105b261ecSmrg }; 9205b261ecSmrg calldata = &rec; 9305b261ecSmrg prv = &rec.rval; 9405b261ecSmrg break; 9505b261ecSmrg } 9605b261ecSmrg case XACE_PROPERTY_ACCESS: { 9705b261ecSmrg XacePropertyAccessRec rec = { 9805b261ecSmrg va_arg(ap, ClientPtr), 9905b261ecSmrg va_arg(ap, WindowPtr), 10005b261ecSmrg va_arg(ap, Atom), 10105b261ecSmrg va_arg(ap, Mask), 10205b261ecSmrg XaceAllowOperation /* default allow */ 10305b261ecSmrg }; 10405b261ecSmrg calldata = &rec; 10505b261ecSmrg prv = &rec.rval; 10605b261ecSmrg break; 10705b261ecSmrg } 10805b261ecSmrg case XACE_DRAWABLE_ACCESS: { 10905b261ecSmrg XaceDrawableAccessRec rec = { 11005b261ecSmrg va_arg(ap, ClientPtr), 11105b261ecSmrg va_arg(ap, DrawablePtr), 11205b261ecSmrg TRUE /* default allow */ 11305b261ecSmrg }; 11405b261ecSmrg calldata = &rec; 11505b261ecSmrg prv = &rec.rval; 11605b261ecSmrg break; 11705b261ecSmrg } 11805b261ecSmrg case XACE_MAP_ACCESS: 11905b261ecSmrg case XACE_BACKGRND_ACCESS: { 12005b261ecSmrg XaceMapAccessRec rec = { 12105b261ecSmrg va_arg(ap, ClientPtr), 12205b261ecSmrg va_arg(ap, WindowPtr), 12305b261ecSmrg TRUE /* default allow */ 12405b261ecSmrg }; 12505b261ecSmrg calldata = &rec; 12605b261ecSmrg prv = &rec.rval; 12705b261ecSmrg break; 12805b261ecSmrg } 12905b261ecSmrg case XACE_EXT_DISPATCH: 13005b261ecSmrg case XACE_EXT_ACCESS: { 13105b261ecSmrg XaceExtAccessRec rec = { 13205b261ecSmrg va_arg(ap, ClientPtr), 13305b261ecSmrg va_arg(ap, ExtensionEntry*), 13405b261ecSmrg TRUE /* default allow */ 13505b261ecSmrg }; 13605b261ecSmrg calldata = &rec; 13705b261ecSmrg prv = &rec.rval; 13805b261ecSmrg break; 13905b261ecSmrg } 14005b261ecSmrg case XACE_HOSTLIST_ACCESS: { 14105b261ecSmrg XaceHostlistAccessRec rec = { 14205b261ecSmrg va_arg(ap, ClientPtr), 14305b261ecSmrg va_arg(ap, Mask), 14405b261ecSmrg TRUE /* default allow */ 14505b261ecSmrg }; 14605b261ecSmrg calldata = &rec; 14705b261ecSmrg prv = &rec.rval; 14805b261ecSmrg break; 14905b261ecSmrg } 15005b261ecSmrg case XACE_SITE_POLICY: { 15105b261ecSmrg XaceSitePolicyRec rec = { 15205b261ecSmrg va_arg(ap, char*), 15305b261ecSmrg va_arg(ap, int), 15405b261ecSmrg FALSE /* default unrecognized */ 15505b261ecSmrg }; 15605b261ecSmrg calldata = &rec; 15705b261ecSmrg prv = &rec.rval; 15805b261ecSmrg break; 15905b261ecSmrg } 16005b261ecSmrg case XACE_DECLARE_EXT_SECURE: { 16105b261ecSmrg XaceDeclareExtSecureRec rec = { 16205b261ecSmrg va_arg(ap, ExtensionEntry*), 16305b261ecSmrg va_arg(ap, Bool) 16405b261ecSmrg }; 16505b261ecSmrg calldata = &rec; 16605b261ecSmrg break; 16705b261ecSmrg } 16805b261ecSmrg case XACE_AUTH_AVAIL: { 16905b261ecSmrg XaceAuthAvailRec rec = { 17005b261ecSmrg va_arg(ap, ClientPtr), 17105b261ecSmrg va_arg(ap, XID) 17205b261ecSmrg }; 17305b261ecSmrg calldata = &rec; 17405b261ecSmrg break; 17505b261ecSmrg } 17605b261ecSmrg case XACE_KEY_AVAIL: { 17705b261ecSmrg XaceKeyAvailRec rec = { 17805b261ecSmrg va_arg(ap, xEventPtr), 17905b261ecSmrg va_arg(ap, DeviceIntPtr), 18005b261ecSmrg va_arg(ap, int) 18105b261ecSmrg }; 18205b261ecSmrg calldata = &rec; 18305b261ecSmrg break; 18405b261ecSmrg } 18505b261ecSmrg case XACE_WINDOW_INIT: { 18605b261ecSmrg XaceWindowRec rec = { 18705b261ecSmrg va_arg(ap, ClientPtr), 18805b261ecSmrg va_arg(ap, WindowPtr) 18905b261ecSmrg }; 19005b261ecSmrg calldata = &rec; 19105b261ecSmrg break; 19205b261ecSmrg } 19305b261ecSmrg case XACE_AUDIT_BEGIN: { 19405b261ecSmrg XaceAuditRec rec = { 19505b261ecSmrg va_arg(ap, ClientPtr), 19605b261ecSmrg 0 19705b261ecSmrg }; 19805b261ecSmrg calldata = &rec; 19905b261ecSmrg break; 20005b261ecSmrg } 20105b261ecSmrg case XACE_AUDIT_END: { 20205b261ecSmrg XaceAuditRec rec = { 20305b261ecSmrg va_arg(ap, ClientPtr), 20405b261ecSmrg va_arg(ap, int) 20505b261ecSmrg }; 20605b261ecSmrg calldata = &rec; 20705b261ecSmrg break; 20805b261ecSmrg } 20905b261ecSmrg default: { 21005b261ecSmrg va_end(ap); 21105b261ecSmrg return 0; /* unimplemented hook number */ 21205b261ecSmrg } 21305b261ecSmrg } 21405b261ecSmrg va_end(ap); 21505b261ecSmrg 21605b261ecSmrg /* call callbacks and return result, if any. */ 21705b261ecSmrg CallCallbacks(&XaceHooks[hook], calldata); 21805b261ecSmrg return prv ? *prv : 0; 21905b261ecSmrg} 22005b261ecSmrg 22105b261ecSmrgstatic int 22205b261ecSmrgProcXaceDispatch(ClientPtr client) 22305b261ecSmrg{ 22405b261ecSmrg REQUEST(xReq); 22505b261ecSmrg 22605b261ecSmrg switch (stuff->data) 22705b261ecSmrg { 22805b261ecSmrg default: 22905b261ecSmrg return BadRequest; 23005b261ecSmrg } 23105b261ecSmrg} /* ProcXaceDispatch */ 23205b261ecSmrg 23305b261ecSmrgstatic int 23405b261ecSmrgSProcXaceDispatch(ClientPtr client) 23505b261ecSmrg{ 23605b261ecSmrg REQUEST(xReq); 23705b261ecSmrg 23805b261ecSmrg switch (stuff->data) 23905b261ecSmrg { 24005b261ecSmrg default: 24105b261ecSmrg return BadRequest; 24205b261ecSmrg } 24305b261ecSmrg} /* SProcXaceDispatch */ 24405b261ecSmrg 24505b261ecSmrg 24605b261ecSmrg/* XaceResetProc 24705b261ecSmrg * 24805b261ecSmrg * Arguments: 24905b261ecSmrg * extEntry is the extension information for the XACE extension. 25005b261ecSmrg * 25105b261ecSmrg * Returns: nothing. 25205b261ecSmrg * 25305b261ecSmrg * Side Effects: 25405b261ecSmrg * Performs any cleanup needed by XACE at server shutdown time. 25505b261ecSmrg */ 25605b261ecSmrgstatic void 25705b261ecSmrgXaceResetProc(ExtensionEntry *extEntry) 25805b261ecSmrg{ 25905b261ecSmrg int i; 26005b261ecSmrg 26105b261ecSmrg for (i=0; i<XACE_NUM_HOOKS; i++) 26205b261ecSmrg { 26305b261ecSmrg DeleteCallbackList(&XaceHooks[i]); 26405b261ecSmrg XaceHooks[i] = NULL; 26505b261ecSmrg } 26605b261ecSmrg} /* XaceResetProc */ 26705b261ecSmrg 26805b261ecSmrg 26905b261ecSmrgstatic int 27005b261ecSmrgXaceCatchDispatchProc(ClientPtr client) 27105b261ecSmrg{ 27205b261ecSmrg REQUEST(xReq); 27305b261ecSmrg int major = stuff->reqType; 27405b261ecSmrg 27505b261ecSmrg if (!ProcVector[major]) 27605b261ecSmrg return (BadRequest); 27705b261ecSmrg 27805b261ecSmrg if (!XaceHook(XACE_CORE_DISPATCH, client)) 27905b261ecSmrg return (BadAccess); 28005b261ecSmrg 28105b261ecSmrg return client->swapped ? 28205b261ecSmrg (* SwappedProcVector[major])(client) : 28305b261ecSmrg (* ProcVector[major])(client); 28405b261ecSmrg} 28505b261ecSmrg 28605b261ecSmrgstatic int 28705b261ecSmrgXaceCatchExtProc(ClientPtr client) 28805b261ecSmrg{ 28905b261ecSmrg REQUEST(xReq); 29005b261ecSmrg int major = stuff->reqType; 29105b261ecSmrg ExtensionEntry *ext = GetExtensionEntry(major); 29205b261ecSmrg 29305b261ecSmrg if (!ext || !ProcVector[major]) 29405b261ecSmrg return (BadRequest); 29505b261ecSmrg 29605b261ecSmrg if (!XaceHook(XACE_EXT_DISPATCH, client, ext)) 29705b261ecSmrg return (BadRequest); /* pretend extension doesn't exist */ 29805b261ecSmrg 29905b261ecSmrg return client->swapped ? 30005b261ecSmrg (* SwappedProcVector[major])(client) : 30105b261ecSmrg (* ProcVector[major])(client); 30205b261ecSmrg} 30305b261ecSmrg 30405b261ecSmrg 30505b261ecSmrg/* SecurityClientStateCallback 30605b261ecSmrg * 30705b261ecSmrg * Arguments: 30805b261ecSmrg * pcbl is &ClientStateCallback. 30905b261ecSmrg * nullata is NULL. 31005b261ecSmrg * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h) 31105b261ecSmrg * which contains information about client state changes. 31205b261ecSmrg * 31305b261ecSmrg * Returns: nothing. 31405b261ecSmrg * 31505b261ecSmrg * Side Effects: 31605b261ecSmrg * 31705b261ecSmrg * If a new client is connecting, its authorization ID is copied to 31805b261ecSmrg * client->authID. If this is a generated authorization, its reference 31905b261ecSmrg * count is bumped, its timer is cancelled if it was running, and its 32005b261ecSmrg * trustlevel is copied to TRUSTLEVEL(client). 32105b261ecSmrg * 32205b261ecSmrg * If a client is disconnecting and the client was using a generated 32305b261ecSmrg * authorization, the authorization's reference count is decremented, and 32405b261ecSmrg * if it is now zero, the timer for this authorization is started. 32505b261ecSmrg */ 32605b261ecSmrg 32705b261ecSmrgstatic void 32805b261ecSmrgXaceClientStateCallback( 32905b261ecSmrg CallbackListPtr *pcbl, 33005b261ecSmrg pointer nulldata, 33105b261ecSmrg pointer calldata) 33205b261ecSmrg{ 33305b261ecSmrg NewClientInfoRec *pci = (NewClientInfoRec *)calldata; 33405b261ecSmrg ClientPtr client = pci->client; 33505b261ecSmrg 33605b261ecSmrg switch (client->clientState) 33705b261ecSmrg { 33805b261ecSmrg case ClientStateRunning: 33905b261ecSmrg { 34005b261ecSmrg client->requestVector = client->swapped ? 34105b261ecSmrg SwappedUntrustedProcVector : UntrustedProcVector; 34205b261ecSmrg break; 34305b261ecSmrg } 34405b261ecSmrg default: break; 34505b261ecSmrg } 34605b261ecSmrg} /* XaceClientStateCallback */ 34705b261ecSmrg 34805b261ecSmrg/* XaceExtensionInit 34905b261ecSmrg * 35005b261ecSmrg * Initialize the XACE Extension 35105b261ecSmrg */ 35205b261ecSmrgvoid XaceExtensionInit(INITARGS) 35305b261ecSmrg{ 35405b261ecSmrg ExtensionEntry *extEntry; 35505b261ecSmrg int i; 35605b261ecSmrg 35705b261ecSmrg if (!AddCallback(&ClientStateCallback, XaceClientStateCallback, NULL)) 35805b261ecSmrg return; 35905b261ecSmrg 36005b261ecSmrg extEntry = AddExtension(XACE_EXTENSION_NAME, 36105b261ecSmrg XaceNumberEvents, XaceNumberErrors, 36205b261ecSmrg ProcXaceDispatch, SProcXaceDispatch, 36305b261ecSmrg XaceResetProc, StandardMinorOpcode); 36405b261ecSmrg 36505b261ecSmrg /* initialize dispatching intercept functions */ 36605b261ecSmrg for (i = 0; i < 128; i++) 36705b261ecSmrg { 36805b261ecSmrg UntrustedProcVector[i] = XaceCatchDispatchProc; 36905b261ecSmrg SwappedUntrustedProcVector[i] = XaceCatchDispatchProc; 37005b261ecSmrg } 37105b261ecSmrg for (i = 128; i < 256; i++) 37205b261ecSmrg { 37305b261ecSmrg UntrustedProcVector[i] = XaceCatchExtProc; 37405b261ecSmrg SwappedUntrustedProcVector[i] = XaceCatchExtProc; 37505b261ecSmrg } 37605b261ecSmrg} 37705b261ecSmrg 37805b261ecSmrg/* XaceCensorImage 37905b261ecSmrg * 38005b261ecSmrg * Called after pScreen->GetImage to prevent pieces or trusted windows from 38105b261ecSmrg * being returned in image data from an untrusted window. 38205b261ecSmrg * 38305b261ecSmrg * Arguments: 38405b261ecSmrg * client is the client doing the GetImage. 38505b261ecSmrg * pVisibleRegion is the visible region of the window. 38605b261ecSmrg * widthBytesLine is the width in bytes of one horizontal line in pBuf. 38705b261ecSmrg * pDraw is the source window. 38805b261ecSmrg * x, y, w, h is the rectangle of image data from pDraw in pBuf. 38905b261ecSmrg * format is the format of the image data in pBuf: ZPixmap or XYPixmap. 39005b261ecSmrg * pBuf is the image data. 39105b261ecSmrg * 39205b261ecSmrg * Returns: nothing. 39305b261ecSmrg * 39405b261ecSmrg * Side Effects: 39505b261ecSmrg * Any part of the rectangle (x, y, w, h) that is outside the visible 39605b261ecSmrg * region of the window will be destroyed (overwritten) in pBuf. 39705b261ecSmrg */ 39805b261ecSmrgvoid 39905b261ecSmrgXaceCensorImage(client, pVisibleRegion, widthBytesLine, pDraw, x, y, w, h, 40005b261ecSmrg format, pBuf) 40105b261ecSmrg ClientPtr client; 40205b261ecSmrg RegionPtr pVisibleRegion; 40305b261ecSmrg long widthBytesLine; 40405b261ecSmrg DrawablePtr pDraw; 40505b261ecSmrg int x, y, w, h; 40605b261ecSmrg unsigned int format; 40705b261ecSmrg char * pBuf; 40805b261ecSmrg{ 40905b261ecSmrg ScreenPtr pScreen; 41005b261ecSmrg RegionRec imageRegion; /* region representing x,y,w,h */ 41105b261ecSmrg RegionRec censorRegion; /* region to obliterate */ 41205b261ecSmrg BoxRec imageBox; 41305b261ecSmrg int nRects; 41405b261ecSmrg 41505b261ecSmrg pScreen = pDraw->pScreen; 41605b261ecSmrg 41705b261ecSmrg imageBox.x1 = x; 41805b261ecSmrg imageBox.y1 = y; 41905b261ecSmrg imageBox.x2 = x + w; 42005b261ecSmrg imageBox.y2 = y + h; 42105b261ecSmrg REGION_INIT(pScreen, &imageRegion, &imageBox, 1); 42205b261ecSmrg REGION_NULL(pScreen, &censorRegion); 42305b261ecSmrg 42405b261ecSmrg /* censorRegion = imageRegion - visibleRegion */ 42505b261ecSmrg REGION_SUBTRACT(pScreen, &censorRegion, &imageRegion, pVisibleRegion); 42605b261ecSmrg nRects = REGION_NUM_RECTS(&censorRegion); 42705b261ecSmrg if (nRects > 0) 42805b261ecSmrg { /* we have something to censor */ 42905b261ecSmrg GCPtr pScratchGC = NULL; 43005b261ecSmrg PixmapPtr pPix = NULL; 43105b261ecSmrg xRectangle *pRects = NULL; 43205b261ecSmrg Bool failed = FALSE; 43305b261ecSmrg int depth = 1; 43405b261ecSmrg int bitsPerPixel = 1; 43505b261ecSmrg int i; 43605b261ecSmrg BoxPtr pBox; 43705b261ecSmrg 43805b261ecSmrg /* convert region to list-of-rectangles for PolyFillRect */ 43905b261ecSmrg 44005b261ecSmrg pRects = (xRectangle *)ALLOCATE_LOCAL(nRects * sizeof(xRectangle *)); 44105b261ecSmrg if (!pRects) 44205b261ecSmrg { 44305b261ecSmrg failed = TRUE; 44405b261ecSmrg goto failSafe; 44505b261ecSmrg } 44605b261ecSmrg for (pBox = REGION_RECTS(&censorRegion), i = 0; 44705b261ecSmrg i < nRects; 44805b261ecSmrg i++, pBox++) 44905b261ecSmrg { 45005b261ecSmrg pRects[i].x = pBox->x1; 45105b261ecSmrg pRects[i].y = pBox->y1 - imageBox.y1; 45205b261ecSmrg pRects[i].width = pBox->x2 - pBox->x1; 45305b261ecSmrg pRects[i].height = pBox->y2 - pBox->y1; 45405b261ecSmrg } 45505b261ecSmrg 45605b261ecSmrg /* use pBuf as a fake pixmap */ 45705b261ecSmrg 45805b261ecSmrg if (format == ZPixmap) 45905b261ecSmrg { 46005b261ecSmrg depth = pDraw->depth; 46105b261ecSmrg bitsPerPixel = pDraw->bitsPerPixel; 46205b261ecSmrg } 46305b261ecSmrg 46405b261ecSmrg pPix = GetScratchPixmapHeader(pDraw->pScreen, w, h, 46505b261ecSmrg depth, bitsPerPixel, 46605b261ecSmrg widthBytesLine, (pointer)pBuf); 46705b261ecSmrg if (!pPix) 46805b261ecSmrg { 46905b261ecSmrg failed = TRUE; 47005b261ecSmrg goto failSafe; 47105b261ecSmrg } 47205b261ecSmrg 47305b261ecSmrg pScratchGC = GetScratchGC(depth, pPix->drawable.pScreen); 47405b261ecSmrg if (!pScratchGC) 47505b261ecSmrg { 47605b261ecSmrg failed = TRUE; 47705b261ecSmrg goto failSafe; 47805b261ecSmrg } 47905b261ecSmrg 48005b261ecSmrg ValidateGC(&pPix->drawable, pScratchGC); 48105b261ecSmrg (* pScratchGC->ops->PolyFillRect)(&pPix->drawable, 48205b261ecSmrg pScratchGC, nRects, pRects); 48305b261ecSmrg 48405b261ecSmrg failSafe: 48505b261ecSmrg if (failed) 48605b261ecSmrg { 48705b261ecSmrg /* Censoring was not completed above. To be safe, wipe out 48805b261ecSmrg * all the image data so that nothing trusted gets out. 48905b261ecSmrg */ 49005b261ecSmrg bzero(pBuf, (int)(widthBytesLine * h)); 49105b261ecSmrg } 49205b261ecSmrg if (pRects) DEALLOCATE_LOCAL(pRects); 49305b261ecSmrg if (pScratchGC) FreeScratchGC(pScratchGC); 49405b261ecSmrg if (pPix) FreeScratchPixmapHeader(pPix); 49505b261ecSmrg } 49605b261ecSmrg REGION_UNINIT(pScreen, &imageRegion); 49705b261ecSmrg REGION_UNINIT(pScreen, &censorRegion); 49805b261ecSmrg} /* XaceCensorImage */ 499