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