xace.c revision 706f2543
1/************************************************************
2
3Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
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
32#define XSERV_t
33#define TRANS_SERVER
34#include <X11/Xtrans/Xtrans.h>
35#include "../os/osdep.h"
36
37_X_EXPORT CallbackListPtr XaceHooks[XACE_NUM_HOOKS] = {0};
38
39/* Special-cased hook functions.  Called by Xserver.
40 */
41int XaceHookDispatch(ClientPtr client, int major)
42{
43    /* Call the audit begin callback, there is no return value. */
44    XaceAuditRec rec = { client, 0 };
45    CallCallbacks(&XaceHooks[XACE_AUDIT_BEGIN], &rec);
46
47    if (major < 128) {
48	/* Call the core dispatch hook */
49	XaceCoreDispatchRec rec = { client, Success /* default allow */ };
50	CallCallbacks(&XaceHooks[XACE_CORE_DISPATCH], &rec);
51	return rec.status;
52    } else {
53	/* Call the extension dispatch hook */
54	ExtensionEntry *ext = GetExtensionEntry(major);
55	XaceExtAccessRec rec = { client, ext, DixUseAccess, Success };
56	if (ext)
57	    CallCallbacks(&XaceHooks[XACE_EXT_DISPATCH], &rec);
58	/* On error, pretend extension doesn't exist */
59	return (rec.status == Success) ? Success : BadRequest;
60    }
61}
62
63int XaceHookPropertyAccess(ClientPtr client, WindowPtr pWin,
64			   PropertyPtr *ppProp, Mask access_mode)
65{
66    XacePropertyAccessRec rec = { client, pWin, ppProp, access_mode, Success };
67    CallCallbacks(&XaceHooks[XACE_PROPERTY_ACCESS], &rec);
68    return rec.status;
69}
70
71int XaceHookSelectionAccess(ClientPtr client,
72			    Selection **ppSel, Mask access_mode)
73{
74    XaceSelectionAccessRec rec = { client, ppSel, access_mode, Success };
75    CallCallbacks(&XaceHooks[XACE_SELECTION_ACCESS], &rec);
76    return rec.status;
77}
78
79void XaceHookAuditEnd(ClientPtr ptr, int result)
80{
81    XaceAuditRec rec = { ptr, result };
82    /* call callbacks, there is no return value. */
83    CallCallbacks(&XaceHooks[XACE_AUDIT_END], &rec);
84}
85
86/* Entry point for hook functions.  Called by Xserver.
87 */
88int XaceHook(int hook, ...)
89{
90    union {
91	XaceResourceAccessRec res;
92	XaceDeviceAccessRec dev;
93	XaceSendAccessRec send;
94	XaceReceiveAccessRec recv;
95	XaceClientAccessRec client;
96	XaceExtAccessRec ext;
97	XaceServerAccessRec server;
98	XaceScreenAccessRec screen;
99	XaceAuthAvailRec auth;
100	XaceKeyAvailRec key;
101    } u;
102    int *prv = NULL;	/* points to return value from callback */
103    va_list ap;		/* argument list */
104
105    if (!XaceHooks[hook])
106	return Success;
107
108    va_start(ap, hook);
109
110    /* Marshal arguments for passing to callback.
111     * Each callback has its own case, which sets up a structure to hold
112     * the arguments and integer return parameter, or in some cases just
113     * sets calldata directly to a single argument (with no return result)
114     */
115    switch (hook)
116    {
117	case XACE_RESOURCE_ACCESS:
118	    u.res.client = va_arg(ap, ClientPtr);
119	    u.res.id = va_arg(ap, XID);
120	    u.res.rtype = va_arg(ap, RESTYPE);
121	    u.res.res = va_arg(ap, pointer);
122	    u.res.ptype = va_arg(ap, RESTYPE);
123	    u.res.parent = va_arg(ap, pointer);
124	    u.res.access_mode = va_arg(ap, Mask);
125	    u.res.status = Success; /* default allow */
126	    prv = &u.res.status;
127	    break;
128	case XACE_DEVICE_ACCESS:
129	    u.dev.client = va_arg(ap, ClientPtr);
130	    u.dev.dev = va_arg(ap, DeviceIntPtr);
131	    u.dev.access_mode = va_arg(ap, Mask);
132	    u.dev.status = Success; /* default allow */
133	    prv = &u.dev.status;
134	    break;
135	case XACE_SEND_ACCESS:
136	    u.send.client = va_arg(ap, ClientPtr);
137	    u.send.dev = va_arg(ap, DeviceIntPtr);
138	    u.send.pWin = va_arg(ap, WindowPtr);
139	    u.send.events = va_arg(ap, xEventPtr);
140	    u.send.count = va_arg(ap, int);
141	    u.send.status = Success; /* default allow */
142	    prv = &u.send.status;
143	    break;
144	case XACE_RECEIVE_ACCESS:
145	    u.recv.client = va_arg(ap, ClientPtr);
146	    u.recv.pWin = va_arg(ap, WindowPtr);
147	    u.recv.events = va_arg(ap, xEventPtr);
148	    u.recv.count = va_arg(ap, int);
149	    u.recv.status = Success; /* default allow */
150	    prv = &u.recv.status;
151	    break;
152	case XACE_CLIENT_ACCESS:
153	    u.client.client = va_arg(ap, ClientPtr);
154	    u.client.target = va_arg(ap, ClientPtr);
155	    u.client.access_mode = va_arg(ap, Mask);
156	    u.client.status = Success; /* default allow */
157	    prv = &u.client.status;
158	    break;
159	case XACE_EXT_ACCESS:
160	    u.ext.client = va_arg(ap, ClientPtr);
161	    u.ext.ext = va_arg(ap, ExtensionEntry*);
162	    u.ext.access_mode = DixGetAttrAccess;
163	    u.ext.status = Success; /* default allow */
164	    prv = &u.ext.status;
165	    break;
166	case XACE_SERVER_ACCESS:
167	    u.server.client = va_arg(ap, ClientPtr);
168	    u.server.access_mode = va_arg(ap, Mask);
169	    u.server.status = Success; /* default allow */
170	    prv = &u.server.status;
171	    break;
172	case XACE_SCREEN_ACCESS:
173	case XACE_SCREENSAVER_ACCESS:
174	    u.screen.client = va_arg(ap, ClientPtr);
175	    u.screen.screen = va_arg(ap, ScreenPtr);
176	    u.screen.access_mode = va_arg(ap, Mask);
177	    u.screen.status = Success; /* default allow */
178	    prv = &u.screen.status;
179	    break;
180	case XACE_AUTH_AVAIL:
181	    u.auth.client = va_arg(ap, ClientPtr);
182	    u.auth.authId = va_arg(ap, XID);
183	    break;
184	case XACE_KEY_AVAIL:
185	    u.key.event = va_arg(ap, xEventPtr);
186	    u.key.keybd = va_arg(ap, DeviceIntPtr);
187	    u.key.count = va_arg(ap, int);
188	    break;
189	default:
190	    va_end(ap);
191	    return 0;	/* unimplemented hook number */
192    }
193    va_end(ap);
194
195    /* call callbacks and return result, if any. */
196    CallCallbacks(&XaceHooks[hook], &u);
197    return prv ? *prv : Success;
198}
199
200/* XaceCensorImage
201 *
202 * Called after pScreen->GetImage to prevent pieces or trusted windows from
203 * being returned in image data from an untrusted window.
204 *
205 * Arguments:
206 *	client is the client doing the GetImage.
207 *      pVisibleRegion is the visible region of the window.
208 *	widthBytesLine is the width in bytes of one horizontal line in pBuf.
209 *	pDraw is the source window.
210 *	x, y, w, h is the rectangle of image data from pDraw in pBuf.
211 *	format is the format of the image data in pBuf: ZPixmap or XYPixmap.
212 *	pBuf is the image data.
213 *
214 * Returns: nothing.
215 *
216 * Side Effects:
217 *	Any part of the rectangle (x, y, w, h) that is outside the visible
218 *	region of the window will be destroyed (overwritten) in pBuf.
219 */
220void
221XaceCensorImage(
222	ClientPtr client,
223	RegionPtr pVisibleRegion,
224	long widthBytesLine,
225	DrawablePtr pDraw,
226	int x, int y, int w, int h,
227	unsigned int format,
228	char *pBuf)
229{
230    RegionRec imageRegion;  /* region representing x,y,w,h */
231    RegionRec censorRegion; /* region to obliterate */
232    BoxRec imageBox;
233    int nRects;
234
235    imageBox.x1 = x;
236    imageBox.y1 = y;
237    imageBox.x2 = x + w;
238    imageBox.y2 = y + h;
239    RegionInit(&imageRegion, &imageBox, 1);
240    RegionNull(&censorRegion);
241
242    /* censorRegion = imageRegion - visibleRegion */
243    RegionSubtract(&censorRegion, &imageRegion, pVisibleRegion);
244    nRects = RegionNumRects(&censorRegion);
245    if (nRects > 0)
246    { /* we have something to censor */
247	GCPtr pScratchGC = NULL;
248	PixmapPtr pPix = NULL;
249	xRectangle *pRects = NULL;
250	Bool failed = FALSE;
251	int depth = 1;
252	int bitsPerPixel = 1;
253	int i;
254	BoxPtr pBox;
255
256	/* convert region to list-of-rectangles for PolyFillRect */
257
258	pRects = malloc(nRects * sizeof(xRectangle));
259	if (!pRects)
260	{
261	    failed = TRUE;
262	    goto failSafe;
263	}
264	for (pBox = RegionRects(&censorRegion), i = 0;
265	     i < nRects;
266	     i++, pBox++)
267	{
268	    pRects[i].x = pBox->x1;
269	    pRects[i].y = pBox->y1 - imageBox.y1;
270	    pRects[i].width  = pBox->x2 - pBox->x1;
271	    pRects[i].height = pBox->y2 - pBox->y1;
272	}
273
274	/* use pBuf as a fake pixmap */
275
276	if (format == ZPixmap)
277	{
278	    depth = pDraw->depth;
279	    bitsPerPixel = pDraw->bitsPerPixel;
280	}
281
282	pPix = GetScratchPixmapHeader(pDraw->pScreen, w, h,
283		    depth, bitsPerPixel,
284		    widthBytesLine, (pointer)pBuf);
285	if (!pPix)
286	{
287	    failed = TRUE;
288	    goto failSafe;
289	}
290
291	pScratchGC = GetScratchGC(depth, pPix->drawable.pScreen);
292	if (!pScratchGC)
293	{
294	    failed = TRUE;
295	    goto failSafe;
296	}
297
298	ValidateGC(&pPix->drawable, pScratchGC);
299	(* pScratchGC->ops->PolyFillRect)(&pPix->drawable,
300			    pScratchGC, nRects, pRects);
301
302    failSafe:
303	if (failed)
304	{
305	    /* Censoring was not completed above.  To be safe, wipe out
306	     * all the image data so that nothing trusted gets out.
307	     */
308	    memset(pBuf, 0, (int)(widthBytesLine * h));
309	}
310	free(pRects);
311	if (pScratchGC) FreeScratchGC(pScratchGC);
312	if (pPix)       FreeScratchPixmapHeader(pPix);
313    }
314    RegionUninit(&imageRegion);
315    RegionUninit(&censorRegion);
316} /* XaceCensorImage */
317
318/*
319 * Xtrans wrappers for use by modules
320 */
321int XaceGetConnectionNumber(ClientPtr client)
322{
323    XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn;
324    return _XSERVTransGetConnectionNumber(ci);
325}
326
327int XaceIsLocal(ClientPtr client)
328{
329    XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn;
330    return _XSERVTransIsLocal(ci);
331}
332