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