1 /************************************************************
2
3 Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 this permission notice appear in supporting documentation. This permission
8 notice shall be included in all copies or substantial portions of the
9 Software.
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 CONNECTION 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
37 int
XaceHookDispatch(ClientPtr client,int major)38 XaceHookDispatch(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
49 int
XaceHookPropertyAccess(ClientPtr client,WindowPtr pWin,PropertyPtr * ppProp,Mask access_mode)50 XaceHookPropertyAccess(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
58 int
XaceHookSelectionAccess(ClientPtr client,Selection ** ppSel,Mask access_mode)59 XaceHookSelectionAccess(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 */
68 int
XaceHook(int hook,...)69 XaceHook(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 */
199 int
XaceHookIsSet(int hook)200 XaceHookIsSet(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 */
227 void
XaceCensorImage(ClientPtr client,RegionPtr pVisibleRegion,long widthBytesLine,DrawablePtr pDraw,int x,int y,int w,int h,unsigned int format,char * pBuf)228 XaceCensorImage(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 */
318 int
XaceGetConnectionNumber(ClientPtr client)319 XaceGetConnectionNumber(ClientPtr client)
320 {
321 return GetClientFd(client);
322 }
323
324 int
XaceIsLocal(ClientPtr client)325 XaceIsLocal(ClientPtr client)
326 {
327 return ClientIsLocal(client);
328 }
329