xace.c revision 541282ce
1/************************************************************
2
3Author: Eamon Walsh <ewalsh@epoch.ncsc.mil>
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7this permission notice appear in supporting documentation.  This permission
8notice shall be included in all copies or substantial portions of the
9Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
14AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
18********************************************************/
19
20#ifdef HAVE_DIX_CONFIG_H
21#include <dix-config.h>
22#endif
23
24#include <stdarg.h>
25#include "scrnintstr.h"
26#include "extnsionst.h"
27#include "pixmapstr.h"
28#include "regionstr.h"
29#include "gcstruct.h"
30#include "xacestr.h"
31
32CallbackListPtr XaceHooks[XACE_NUM_HOOKS] = {0};
33
34/* Special-cased hook functions.  Called by Xserver.
35 */
36int XaceHookDispatch(ClientPtr client, int major)
37{
38    /* Call the audit begin callback, there is no return value. */
39    XaceAuditRec rec = { client, 0 };
40    CallCallbacks(&XaceHooks[XACE_AUDIT_BEGIN], &rec);
41
42    if (major < 128) {
43	/* Call the core dispatch hook */
44	XaceCoreDispatchRec rec = { client, Success /* default allow */ };
45	CallCallbacks(&XaceHooks[XACE_CORE_DISPATCH], &rec);
46	return rec.status;
47    } else {
48	/* Call the extension dispatch hook */
49	ExtensionEntry *ext = GetExtensionEntry(major);
50	XaceExtAccessRec rec = { client, ext, DixUseAccess, Success };
51	if (ext)
52	    CallCallbacks(&XaceHooks[XACE_EXT_DISPATCH], &rec);
53	/* On error, pretend extension doesn't exist */
54	return (rec.status == Success) ? Success : BadRequest;
55    }
56}
57
58int XaceHookPropertyAccess(ClientPtr client, WindowPtr pWin,
59			   PropertyPtr *ppProp, Mask access_mode)
60{
61    XacePropertyAccessRec rec = { client, pWin, ppProp, access_mode, Success };
62    CallCallbacks(&XaceHooks[XACE_PROPERTY_ACCESS], &rec);
63    return rec.status;
64}
65
66int XaceHookSelectionAccess(ClientPtr client,
67			    Selection **ppSel, Mask access_mode)
68{
69    XaceSelectionAccessRec rec = { client, ppSel, access_mode, Success };
70    CallCallbacks(&XaceHooks[XACE_SELECTION_ACCESS], &rec);
71    return rec.status;
72}
73
74void XaceHookAuditEnd(ClientPtr ptr, int result)
75{
76    XaceAuditRec rec = { ptr, result };
77    /* call callbacks, there is no return value. */
78    CallCallbacks(&XaceHooks[XACE_AUDIT_END], &rec);
79}
80
81/* Entry point for hook functions.  Called by Xserver.
82 */
83int XaceHook(int hook, ...)
84{
85    pointer calldata;	/* data passed to callback */
86    int *prv = NULL;	/* points to return value from callback */
87    va_list ap;		/* argument list */
88    va_start(ap, hook);
89
90    /* Marshal arguments for passing to callback.
91     * Each callback has its own case, which sets up a structure to hold
92     * the arguments and integer return parameter, or in some cases just
93     * sets calldata directly to a single argument (with no return result)
94     */
95    switch (hook)
96    {
97	case XACE_RESOURCE_ACCESS: {
98	    XaceResourceAccessRec rec;
99	    rec.client = va_arg(ap, ClientPtr);
100	    rec.id = va_arg(ap, XID);
101	    rec.rtype = va_arg(ap, RESTYPE);
102	    rec.res = va_arg(ap, pointer);
103	    rec.ptype = va_arg(ap, RESTYPE);
104	    rec.parent = va_arg(ap, pointer);
105	    rec.access_mode = va_arg(ap, Mask);
106	    rec.status = Success; /* default allow */
107	    calldata = &rec;
108	    prv = &rec.status;
109	    break;
110	}
111	case XACE_DEVICE_ACCESS: {
112	    XaceDeviceAccessRec rec;
113	    rec.client = va_arg(ap, ClientPtr);
114	    rec.dev = va_arg(ap, DeviceIntPtr);
115	    rec.access_mode = va_arg(ap, Mask);
116	    rec.status = Success; /* default allow */
117	    calldata = &rec;
118	    prv = &rec.status;
119	    break;
120	}
121	case XACE_SEND_ACCESS: {
122	    XaceSendAccessRec rec;
123	    rec.client = va_arg(ap, ClientPtr);
124	    rec.dev = va_arg(ap, DeviceIntPtr);
125	    rec.pWin = va_arg(ap, WindowPtr);
126	    rec.events = va_arg(ap, xEventPtr);
127	    rec.count = va_arg(ap, int);
128	    rec.status = Success; /* default allow */
129	    calldata = &rec;
130	    prv = &rec.status;
131	    break;
132	}
133	case XACE_RECEIVE_ACCESS: {
134	    XaceReceiveAccessRec rec;
135	    rec.client = va_arg(ap, ClientPtr);
136	    rec.pWin = va_arg(ap, WindowPtr);
137	    rec.events = va_arg(ap, xEventPtr);
138	    rec.count = va_arg(ap, int);
139	    rec.status = Success; /* default allow */
140	    calldata = &rec;
141	    prv = &rec.status;
142	    break;
143	}
144	case XACE_CLIENT_ACCESS: {
145	    XaceClientAccessRec rec;
146	    rec.client = va_arg(ap, ClientPtr);
147	    rec.target = va_arg(ap, ClientPtr);
148	    rec.access_mode = va_arg(ap, Mask);
149	    rec.status = Success; /* default allow */
150	    calldata = &rec;
151	    prv = &rec.status;
152	    break;
153	}
154	case XACE_EXT_ACCESS: {
155	    XaceExtAccessRec rec;
156	    rec.client = va_arg(ap, ClientPtr);
157	    rec.ext = va_arg(ap, ExtensionEntry*);
158	    rec.access_mode = DixGetAttrAccess;
159	    rec.status = Success; /* default allow */
160	    calldata = &rec;
161	    prv = &rec.status;
162	    break;
163	}
164	case XACE_SERVER_ACCESS: {
165	    XaceServerAccessRec rec;
166	    rec.client = va_arg(ap, ClientPtr);
167	    rec.access_mode = va_arg(ap, Mask);
168	    rec.status = Success; /* default allow */
169	    calldata = &rec;
170	    prv = &rec.status;
171	    break;
172	}
173	case XACE_SCREEN_ACCESS:
174	case XACE_SCREENSAVER_ACCESS: {
175	    XaceScreenAccessRec rec;
176	    rec.client = va_arg(ap, ClientPtr);
177	    rec.screen = va_arg(ap, ScreenPtr);
178	    rec.access_mode = va_arg(ap, Mask);
179	    rec.status = Success; /* default allow */
180	    calldata = &rec;
181	    prv = &rec.status;
182	    break;
183	}
184	case XACE_AUTH_AVAIL: {
185	    XaceAuthAvailRec rec;
186	    rec.client = va_arg(ap, ClientPtr);
187	    rec.authId = va_arg(ap, XID);
188	    calldata = &rec;
189	    break;
190	}
191	case XACE_KEY_AVAIL: {
192	    XaceKeyAvailRec rec;
193	    rec.event = va_arg(ap, xEventPtr);
194	    rec.keybd = va_arg(ap, DeviceIntPtr);
195	    rec.count = va_arg(ap, int);
196	    calldata = &rec;
197	    break;
198	}
199	default: {
200	    va_end(ap);
201	    return 0;	/* unimplemented hook number */
202	}
203    }
204    va_end(ap);
205
206    /* call callbacks and return result, if any. */
207    CallCallbacks(&XaceHooks[hook], calldata);
208    return prv ? *prv : Success;
209}
210
211/* XaceCensorImage
212 *
213 * Called after pScreen->GetImage to prevent pieces or trusted windows from
214 * being returned in image data from an untrusted window.
215 *
216 * Arguments:
217 *	client is the client doing the GetImage.
218 *      pVisibleRegion is the visible region of the window.
219 *	widthBytesLine is the width in bytes of one horizontal line in pBuf.
220 *	pDraw is the source window.
221 *	x, y, w, h is the rectangle of image data from pDraw in pBuf.
222 *	format is the format of the image data in pBuf: ZPixmap or XYPixmap.
223 *	pBuf is the image data.
224 *
225 * Returns: nothing.
226 *
227 * Side Effects:
228 *	Any part of the rectangle (x, y, w, h) that is outside the visible
229 *	region of the window will be destroyed (overwritten) in pBuf.
230 */
231void
232XaceCensorImage(client, pVisibleRegion, widthBytesLine, pDraw, x, y, w, h,
233		format, pBuf)
234    ClientPtr client;
235    RegionPtr pVisibleRegion;
236    long widthBytesLine;
237    DrawablePtr pDraw;
238    int x, y, w, h;
239    unsigned int format;
240    char * pBuf;
241{
242    ScreenPtr pScreen;
243    RegionRec imageRegion;  /* region representing x,y,w,h */
244    RegionRec censorRegion; /* region to obliterate */
245    BoxRec imageBox;
246    int nRects;
247
248    pScreen = pDraw->pScreen;
249
250    imageBox.x1 = x;
251    imageBox.y1 = y;
252    imageBox.x2 = x + w;
253    imageBox.y2 = y + h;
254    REGION_INIT(pScreen, &imageRegion, &imageBox, 1);
255    REGION_NULL(pScreen, &censorRegion);
256
257    /* censorRegion = imageRegion - visibleRegion */
258    REGION_SUBTRACT(pScreen, &censorRegion, &imageRegion, pVisibleRegion);
259    nRects = REGION_NUM_RECTS(&censorRegion);
260    if (nRects > 0)
261    { /* we have something to censor */
262	GCPtr pScratchGC = NULL;
263	PixmapPtr pPix = NULL;
264	xRectangle *pRects = NULL;
265	Bool failed = FALSE;
266	int depth = 1;
267	int bitsPerPixel = 1;
268	int i;
269	BoxPtr pBox;
270
271	/* convert region to list-of-rectangles for PolyFillRect */
272
273	pRects = (xRectangle *)xalloc(nRects * sizeof(xRectangle));
274	if (!pRects)
275	{
276	    failed = TRUE;
277	    goto failSafe;
278	}
279	for (pBox = REGION_RECTS(&censorRegion), i = 0;
280	     i < nRects;
281	     i++, pBox++)
282	{
283	    pRects[i].x = pBox->x1;
284	    pRects[i].y = pBox->y1 - imageBox.y1;
285	    pRects[i].width  = pBox->x2 - pBox->x1;
286	    pRects[i].height = pBox->y2 - pBox->y1;
287	}
288
289	/* use pBuf as a fake pixmap */
290
291	if (format == ZPixmap)
292	{
293	    depth = pDraw->depth;
294	    bitsPerPixel = pDraw->bitsPerPixel;
295	}
296
297	pPix = GetScratchPixmapHeader(pDraw->pScreen, w, h,
298		    depth, bitsPerPixel,
299		    widthBytesLine, (pointer)pBuf);
300	if (!pPix)
301	{
302	    failed = TRUE;
303	    goto failSafe;
304	}
305
306	pScratchGC = GetScratchGC(depth, pPix->drawable.pScreen);
307	if (!pScratchGC)
308	{
309	    failed = TRUE;
310	    goto failSafe;
311	}
312
313	ValidateGC(&pPix->drawable, pScratchGC);
314	(* pScratchGC->ops->PolyFillRect)(&pPix->drawable,
315			    pScratchGC, nRects, pRects);
316
317    failSafe:
318	if (failed)
319	{
320	    /* Censoring was not completed above.  To be safe, wipe out
321	     * all the image data so that nothing trusted gets out.
322	     */
323	    bzero(pBuf, (int)(widthBytesLine * h));
324	}
325	if (pRects)     xfree(pRects);
326	if (pScratchGC) FreeScratchGC(pScratchGC);
327	if (pPix)       FreeScratchPixmapHeader(pPix);
328    }
329    REGION_UNINIT(pScreen, &imageRegion);
330    REGION_UNINIT(pScreen, &censorRegion);
331} /* XaceCensorImage */
332