1 /***********************************************************
2
3 Copyright 1987, 1998 The Open Group
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 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27 All Rights Reserved
28
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
36
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43 SOFTWARE.
44
45 ******************************************************************/
46
47 #ifdef HAVE_DIX_CONFIG_H
48 #include <dix-config.h>
49 #endif
50
51 #include <X11/X.h>
52 #include <X11/Xproto.h>
53 #include "windowstr.h"
54 #include "propertyst.h"
55 #include "dixstruct.h"
56 #include "dispatch.h"
57 #include "swaprep.h"
58 #include "xace.h"
59
60 /*****************************************************************
61 * Property Stuff
62 *
63 * dixLookupProperty, dixChangeProperty, DeleteProperty
64 *
65 * Properties belong to windows. The list of properties should not be
66 * traversed directly. Instead, use the three functions listed above.
67 *
68 *****************************************************************/
69
70 #ifdef notdef
71 static void
PrintPropertys(WindowPtr pWin)72 PrintPropertys(WindowPtr pWin)
73 {
74 PropertyPtr pProp;
75 int j;
76
77 pProp = pWin->userProps;
78 while (pProp) {
79 ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type);
80 ErrorF("[dix] property format: %d\n", pProp->format);
81 ErrorF("[dix] property data: \n");
82 for (j = 0; j < (pProp->format / 8) * pProp->size; j++)
83 ErrorF("[dix] %c\n", pProp->data[j]);
84 pProp = pProp->next;
85 }
86 }
87 #endif
88
89 int
dixLookupProperty(PropertyPtr * result,WindowPtr pWin,Atom propertyName,ClientPtr client,Mask access_mode)90 dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName,
91 ClientPtr client, Mask access_mode)
92 {
93 PropertyPtr pProp;
94 int rc = BadMatch;
95
96 client->errorValue = propertyName;
97
98 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
99 if (pProp->propertyName == propertyName)
100 break;
101
102 if (pProp)
103 rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode);
104 *result = pProp;
105 return rc;
106 }
107
108 CallbackListPtr PropertyStateCallback;
109
110 static void
deliverPropertyNotifyEvent(WindowPtr pWin,int state,PropertyPtr pProp)111 deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp)
112 {
113 xEvent event;
114 PropertyStateRec rec = {
115 .win = pWin,
116 .prop = pProp,
117 .state = state
118 };
119 UpdateCurrentTimeIf();
120 event = (xEvent) {
121 .u.property.window = pWin->drawable.id,
122 .u.property.state = state,
123 .u.property.atom = pProp->propertyName,
124 .u.property.time = currentTime.milliseconds,
125 };
126 event.u.u.type = PropertyNotify;
127
128 CallCallbacks(&PropertyStateCallback, &rec);
129 DeliverEvents(pWin, &event, 1, (WindowPtr) NULL);
130 }
131
132 int
ProcRotateProperties(ClientPtr client)133 ProcRotateProperties(ClientPtr client)
134 {
135 int i, j, delta, rc;
136
137 REQUEST(xRotatePropertiesReq);
138 WindowPtr pWin;
139 Atom *atoms;
140 PropertyPtr *props; /* array of pointer */
141 PropertyPtr pProp, saved;
142
143 REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2);
144 UpdateCurrentTime();
145 rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
146 if (rc != Success || stuff->nAtoms <= 0)
147 return rc;
148
149 atoms = (Atom *) &stuff[1];
150 props = xallocarray(stuff->nAtoms, sizeof(PropertyPtr));
151 saved = xallocarray(stuff->nAtoms, sizeof(PropertyRec));
152 if (!props || !saved) {
153 rc = BadAlloc;
154 goto out;
155 }
156
157 for (i = 0; i < stuff->nAtoms; i++) {
158 if (!ValidAtom(atoms[i])) {
159 rc = BadAtom;
160 client->errorValue = atoms[i];
161 goto out;
162 }
163 for (j = i + 1; j < stuff->nAtoms; j++)
164 if (atoms[j] == atoms[i]) {
165 rc = BadMatch;
166 goto out;
167 }
168
169 rc = dixLookupProperty(&pProp, pWin, atoms[i], client,
170 DixReadAccess | DixWriteAccess);
171 if (rc != Success)
172 goto out;
173
174 props[i] = pProp;
175 saved[i] = *pProp;
176 }
177 delta = stuff->nPositions;
178
179 /* If the rotation is a complete 360 degrees, then moving the properties
180 around and generating PropertyNotify events should be skipped. */
181
182 if (abs(delta) % stuff->nAtoms) {
183 while (delta < 0) /* faster if abs value is small */
184 delta += stuff->nAtoms;
185 for (i = 0; i < stuff->nAtoms; i++) {
186 j = (i + delta) % stuff->nAtoms;
187 deliverPropertyNotifyEvent(pWin, PropertyNewValue, props[i]);
188
189 /* Preserve name and devPrivates */
190 props[j]->type = saved[i].type;
191 props[j]->format = saved[i].format;
192 props[j]->size = saved[i].size;
193 props[j]->data = saved[i].data;
194 }
195 }
196 out:
197 free(saved);
198 free(props);
199 return rc;
200 }
201
202 int
ProcChangeProperty(ClientPtr client)203 ProcChangeProperty(ClientPtr client)
204 {
205 WindowPtr pWin;
206 char format, mode;
207 unsigned long len;
208 int sizeInBytes, totalSize, err;
209
210 REQUEST(xChangePropertyReq);
211
212 REQUEST_AT_LEAST_SIZE(xChangePropertyReq);
213 UpdateCurrentTime();
214 format = stuff->format;
215 mode = stuff->mode;
216 if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
217 (mode != PropModePrepend)) {
218 client->errorValue = mode;
219 return BadValue;
220 }
221 if ((format != 8) && (format != 16) && (format != 32)) {
222 client->errorValue = format;
223 return BadValue;
224 }
225 len = stuff->nUnits;
226 if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq)))
227 return BadLength;
228 sizeInBytes = format >> 3;
229 totalSize = len * sizeInBytes;
230 REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);
231
232 err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
233 if (err != Success)
234 return err;
235 if (!ValidAtom(stuff->property)) {
236 client->errorValue = stuff->property;
237 return BadAtom;
238 }
239 if (!ValidAtom(stuff->type)) {
240 client->errorValue = stuff->type;
241 return BadAtom;
242 }
243
244 err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type,
245 (int) format, (int) mode, len, &stuff[1],
246 TRUE);
247 if (err != Success)
248 return err;
249 else
250 return Success;
251 }
252
253 int
dixChangeWindowProperty(ClientPtr pClient,WindowPtr pWin,Atom property,Atom type,int format,int mode,unsigned long len,void * value,Bool sendevent)254 dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
255 Atom type, int format, int mode, unsigned long len,
256 void *value, Bool sendevent)
257 {
258 PropertyPtr pProp;
259 PropertyRec savedProp;
260 int sizeInBytes, totalSize, rc;
261 unsigned char *data;
262 Mask access_mode;
263
264 sizeInBytes = format >> 3;
265 totalSize = len * sizeInBytes;
266 access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess;
267
268 /* first see if property already exists */
269 rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode);
270
271 if (rc == BadMatch) { /* just add to list */
272 if (!pWin->optional && !MakeWindowOptional(pWin))
273 return BadAlloc;
274 pProp = dixAllocateObjectWithPrivates(PropertyRec, PRIVATE_PROPERTY);
275 if (!pProp)
276 return BadAlloc;
277 data = malloc(totalSize);
278 if (!data && len) {
279 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
280 return BadAlloc;
281 }
282 memcpy(data, value, totalSize);
283 pProp->propertyName = property;
284 pProp->type = type;
285 pProp->format = format;
286 pProp->data = data;
287 pProp->size = len;
288 rc = XaceHookPropertyAccess(pClient, pWin, &pProp,
289 DixCreateAccess | DixWriteAccess);
290 if (rc != Success) {
291 free(data);
292 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
293 pClient->errorValue = property;
294 return rc;
295 }
296 pProp->next = pWin->optional->userProps;
297 pWin->optional->userProps = pProp;
298 }
299 else if (rc == Success) {
300 /* To append or prepend to a property the request format and type
301 must match those of the already defined property. The
302 existing format and type are irrelevant when using the mode
303 "PropModeReplace" since they will be written over. */
304
305 if ((format != pProp->format) && (mode != PropModeReplace))
306 return BadMatch;
307 if ((pProp->type != type) && (mode != PropModeReplace))
308 return BadMatch;
309
310 /* save the old values for later */
311 savedProp = *pProp;
312
313 if (mode == PropModeReplace) {
314 data = malloc(totalSize);
315 if (!data && len)
316 return BadAlloc;
317 memcpy(data, value, totalSize);
318 pProp->data = data;
319 pProp->size = len;
320 pProp->type = type;
321 pProp->format = format;
322 }
323 else if (len == 0) {
324 /* do nothing */
325 }
326 else if (mode == PropModeAppend) {
327 data = xallocarray(pProp->size + len, sizeInBytes);
328 if (!data)
329 return BadAlloc;
330 memcpy(data, pProp->data, pProp->size * sizeInBytes);
331 memcpy(data + pProp->size * sizeInBytes, value, totalSize);
332 pProp->data = data;
333 pProp->size += len;
334 }
335 else if (mode == PropModePrepend) {
336 data = xallocarray(len + pProp->size, sizeInBytes);
337 if (!data)
338 return BadAlloc;
339 memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes);
340 memcpy(data, value, totalSize);
341 pProp->data = data;
342 pProp->size += len;
343 }
344
345 /* Allow security modules to check the new content */
346 access_mode |= DixPostAccess;
347 rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode);
348 if (rc == Success) {
349 if (savedProp.data != pProp->data)
350 free(savedProp.data);
351 }
352 else {
353 if (savedProp.data != pProp->data)
354 free(pProp->data);
355 *pProp = savedProp;
356 return rc;
357 }
358 }
359 else
360 return rc;
361
362 if (sendevent)
363 deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp);
364
365 return Success;
366 }
367
368 int
DeleteProperty(ClientPtr client,WindowPtr pWin,Atom propName)369 DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName)
370 {
371 PropertyPtr pProp, prevProp;
372 int rc;
373
374 rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess);
375 if (rc == BadMatch)
376 return Success; /* Succeed if property does not exist */
377
378 if (rc == Success) {
379 if (pWin->optional->userProps == pProp) {
380 /* Takes care of head */
381 if (!(pWin->optional->userProps = pProp->next))
382 CheckWindowOptionalNeed(pWin);
383 }
384 else {
385 /* Need to traverse to find the previous element */
386 prevProp = pWin->optional->userProps;
387 while (prevProp->next != pProp)
388 prevProp = prevProp->next;
389 prevProp->next = pProp->next;
390 }
391
392 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
393 free(pProp->data);
394 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
395 }
396 return rc;
397 }
398
399 void
DeleteAllWindowProperties(WindowPtr pWin)400 DeleteAllWindowProperties(WindowPtr pWin)
401 {
402 PropertyPtr pProp, pNextProp;
403
404 pProp = wUserProps(pWin);
405 while (pProp) {
406 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
407 pNextProp = pProp->next;
408 free(pProp->data);
409 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
410 pProp = pNextProp;
411 }
412
413 if (pWin->optional)
414 pWin->optional->userProps = NULL;
415 }
416
417 static int
NullPropertyReply(ClientPtr client,ATOM propertyType,int format)418 NullPropertyReply(ClientPtr client, ATOM propertyType, int format)
419 {
420 xGetPropertyReply reply = {
421 .type = X_Reply,
422 .format = format,
423 .sequenceNumber = client->sequence,
424 .length = 0,
425 .propertyType = propertyType,
426 .bytesAfter = 0,
427 .nItems = 0
428 };
429 WriteReplyToClient(client, sizeof(xGenericReply), &reply);
430 return Success;
431 }
432
433 /*****************
434 * GetProperty
435 * If type Any is specified, returns the property from the specified
436 * window regardless of its type. If a type is specified, returns the
437 * property only if its type equals the specified type.
438 * If delete is True and a property is returned, the property is also
439 * deleted from the window and a PropertyNotify event is generated on the
440 * window.
441 *****************/
442
443 int
ProcGetProperty(ClientPtr client)444 ProcGetProperty(ClientPtr client)
445 {
446 PropertyPtr pProp, prevProp;
447 unsigned long n, len, ind;
448 int rc;
449 WindowPtr pWin;
450 xGetPropertyReply reply;
451 Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
452
453 REQUEST(xGetPropertyReq);
454
455 REQUEST_SIZE_MATCH(xGetPropertyReq);
456 if (stuff->delete) {
457 UpdateCurrentTime();
458 win_mode |= DixSetPropAccess;
459 prop_mode |= DixDestroyAccess;
460 }
461 rc = dixLookupWindow(&pWin, stuff->window, client, win_mode);
462 if (rc != Success)
463 return rc;
464
465 if (!ValidAtom(stuff->property)) {
466 client->errorValue = stuff->property;
467 return BadAtom;
468 }
469 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) {
470 client->errorValue = stuff->delete;
471 return BadValue;
472 }
473 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) {
474 client->errorValue = stuff->type;
475 return BadAtom;
476 }
477
478 rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode);
479 if (rc == BadMatch)
480 return NullPropertyReply(client, None, 0);
481 else if (rc != Success)
482 return rc;
483
484 /* If the request type and actual type don't match. Return the
485 property information, but not the data. */
486
487 if (((stuff->type != pProp->type) && (stuff->type != AnyPropertyType))
488 ) {
489 reply = (xGetPropertyReply) {
490 .type = X_Reply,
491 .sequenceNumber = client->sequence,
492 .bytesAfter = pProp->size,
493 .format = pProp->format,
494 .length = 0,
495 .nItems = 0,
496 .propertyType = pProp->type
497 };
498 WriteReplyToClient(client, sizeof(xGenericReply), &reply);
499 return Success;
500 }
501
502 /*
503 * Return type, format, value to client
504 */
505 n = (pProp->format / 8) * pProp->size; /* size (bytes) of prop */
506 ind = stuff->longOffset << 2;
507
508 /* If longOffset is invalid such that it causes "len" to
509 be negative, it's a value error. */
510
511 if (n < ind) {
512 client->errorValue = stuff->longOffset;
513 return BadValue;
514 }
515
516 len = min(n - ind, 4 * stuff->longLength);
517
518 reply = (xGetPropertyReply) {
519 .type = X_Reply,
520 .sequenceNumber = client->sequence,
521 .bytesAfter = n - (ind + len),
522 .format = pProp->format,
523 .length = bytes_to_int32(len),
524 .nItems = len / (pProp->format / 8),
525 .propertyType = pProp->type
526 };
527
528 if (stuff->delete && (reply.bytesAfter == 0))
529 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
530
531 WriteReplyToClient(client, sizeof(xGenericReply), &reply);
532 if (len) {
533 switch (reply.format) {
534 case 32:
535 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
536 break;
537 case 16:
538 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
539 break;
540 default:
541 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
542 break;
543 }
544 WriteSwappedDataToClient(client, len, (char *) pProp->data + ind);
545 }
546
547 if (stuff->delete && (reply.bytesAfter == 0)) {
548 /* Delete the Property */
549 if (pWin->optional->userProps == pProp) {
550 /* Takes care of head */
551 if (!(pWin->optional->userProps = pProp->next))
552 CheckWindowOptionalNeed(pWin);
553 }
554 else {
555 /* Need to traverse to find the previous element */
556 prevProp = pWin->optional->userProps;
557 while (prevProp->next != pProp)
558 prevProp = prevProp->next;
559 prevProp->next = pProp->next;
560 }
561
562 free(pProp->data);
563 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
564 }
565 return Success;
566 }
567
568 int
ProcListProperties(ClientPtr client)569 ProcListProperties(ClientPtr client)
570 {
571 Atom *pAtoms = NULL, *temppAtoms;
572 xListPropertiesReply xlpr;
573 int rc, numProps = 0;
574 WindowPtr pWin;
575 PropertyPtr pProp, realProp;
576
577 REQUEST(xResourceReq);
578
579 REQUEST_SIZE_MATCH(xResourceReq);
580 rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess);
581 if (rc != Success)
582 return rc;
583
584 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
585 numProps++;
586
587 if (numProps && !(pAtoms = xallocarray(numProps, sizeof(Atom))))
588 return BadAlloc;
589
590 numProps = 0;
591 temppAtoms = pAtoms;
592 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) {
593 realProp = pProp;
594 rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess);
595 if (rc == Success && realProp == pProp) {
596 *temppAtoms++ = pProp->propertyName;
597 numProps++;
598 }
599 }
600
601 xlpr = (xListPropertiesReply) {
602 .type = X_Reply,
603 .sequenceNumber = client->sequence,
604 .length = bytes_to_int32(numProps * sizeof(Atom)),
605 .nProperties = numProps
606 };
607 WriteReplyToClient(client, sizeof(xGenericReply), &xlpr);
608 if (numProps) {
609 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
610 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
611 }
612 free(pAtoms);
613 return Success;
614 }
615
616 int
ProcDeleteProperty(ClientPtr client)617 ProcDeleteProperty(ClientPtr client)
618 {
619 WindowPtr pWin;
620
621 REQUEST(xDeletePropertyReq);
622 int result;
623
624 REQUEST_SIZE_MATCH(xDeletePropertyReq);
625 UpdateCurrentTime();
626 result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
627 if (result != Success)
628 return result;
629 if (!ValidAtom(stuff->property)) {
630 client->errorValue = stuff->property;
631 return BadAtom;
632 }
633
634 return DeleteProperty(client, pWin, stuff->property);
635 }
636