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