diff --git a/Xi/Makefile.am b/Xi/Makefile.am index 5d3417e65..e77c8a382 100644 --- a/Xi/Makefile.am +++ b/Xi/Makefile.am @@ -20,7 +20,9 @@ libXi_la_SOURCES = \ chgptr.c \ chgptr.h \ chpkpair.c \ - chpkpair.h \ + chpkpair.h \ + chaccess.c \ + chaccess.h \ closedev.c \ closedev.h \ devbell.c \ @@ -46,6 +48,8 @@ libXi_la_SOURCES = \ getselev.h \ getvers.c \ getvers.h \ + grabacc.c \ + grabacc.h \ grabdev.c \ grabdev.h \ grabdevb.c \ @@ -62,6 +66,8 @@ libXi_la_SOURCES = \ querydp.h \ queryst.c \ queryst.h \ + qryacces.c \ + qryacces.h \ regpair.c \ regpair.h \ selectev.c \ diff --git a/Xi/chaccess.c b/Xi/chaccess.c new file mode 100644 index 000000000..5005e9435 --- /dev/null +++ b/Xi/chaccess.c @@ -0,0 +1,177 @@ +/* + +Copyright 2007 Peter Hutterer + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +#define NEED_EVENTS +#define NEED_REPLIES +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include /* for inputstr.h */ +#include /* Request macro */ +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include "scrnintstr.h" /* screen structure */ +#include +#include +#include "extnsionst.h" +#include "extinit.h" /* LookupDeviceIntRec */ +#include "exevents.h" +#include "exglobals.h" + +#include "chaccess.h" + +/*********************************************************************** + * This procedure allows a client to change window access control. + */ + +int +SProcXChangeWindowAccess(ClientPtr client) +{ + char n; + REQUEST(xChangeWindowAccessReq); + + swaps(&stuff->length, n); + swapl(&stuff->win, n); + return ProcXChangeWindowAccess(client); +} + +int +ProcXChangeWindowAccess(ClientPtr client) +{ + int padding, err, i; + CARD8* deviceids = NULL; + WindowPtr win; + DeviceIntPtr* perm_devices = NULL; + DeviceIntPtr* deny_devices = NULL; + REQUEST(xChangeWindowAccessReq); + REQUEST_AT_LEAST_SIZE(xChangeWindowAccessReq); + + + padding = (4 - ((stuff->npermit + stuff->ndeny) % 4)) % 4; + + if (stuff->length != ((sizeof(xChangeWindowAccessReq) + + (stuff->npermit + stuff->ndeny + padding)) >> 2)) + { + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, + 0, BadLength); + return Success; + } + + + err = dixLookupWindow(&win, stuff->win, client, DixWriteAccess); + if (err != Success) + { + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, + stuff->win, err); + return Success; + } + + /* Are we clearing? if so, ignore the rest */ + if (stuff->clear) + { + err = ACClearWindowAccess(client, win, stuff->clear); + if (err != Success) + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 0, err); + return Success; + } + + if (stuff->npermit || stuff->ndeny) + deviceids = (CARD8*)&stuff[1]; + + if (stuff->npermit) + { + perm_devices = + (DeviceIntPtr*)xalloc(stuff->npermit * sizeof(DeviceIntPtr)); + if (!perm_devices) + { + ErrorF("ProcXChangeWindowAccess: alloc failure.\n"); + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 0, + BadImplementation); + return Success; + } + + /* if one of the devices cannot be accessed, we don't do anything.*/ + for (i = 0; i < stuff->npermit; i++) + { + perm_devices[i] = LookupDeviceIntRec(deviceids[i]); + if (!perm_devices[i]) + { + xfree(perm_devices); + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, + deviceids[i], BadDevice); + return Success; + } + } + } + + if (stuff->ndeny) + { + deny_devices = + (DeviceIntPtr*)xalloc(stuff->ndeny * sizeof(DeviceIntPtr)); + if (!deny_devices) + { + ErrorF("ProcXChangeWindowAccecss: alloc failure.\n"); + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 0, + BadImplementation); + + xfree(perm_devices); + return Success; + } + + for (i = 0; i < stuff->ndeny; i++) + { + deny_devices[i] = + LookupDeviceIntRec(deviceids[i+stuff->npermit]); + + if (!deny_devices[i]) + { + xfree(perm_devices); + xfree(deny_devices); + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, + deviceids[i + stuff->npermit], BadDevice); + return Success; + } + } + } + + err = ACChangeWindowAccess(client, win, stuff->defaultRule, + perm_devices, stuff->npermit, + deny_devices, stuff->ndeny); + if (err != Success) + { + SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, + stuff->win, err); + return Success; + } + + xfree(perm_devices); + xfree(deny_devices); + return Success; +} + diff --git a/Xi/chaccess.h b/Xi/chaccess.h new file mode 100644 index 000000000..8c2c6003e --- /dev/null +++ b/Xi/chaccess.h @@ -0,0 +1,39 @@ +/* + +Copyright 2007 Peter Hutterer + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef CHACCESS_H +#define CHACCESS_H 1 + +int SProcXChangeWindowAccess(ClientPtr /* client */); +int ProcXChangeWindowAccess(ClientPtr /* client */); + +#endif /* CHACCESS_H */ diff --git a/Xi/extinit.c b/Xi/extinit.c index cf4f509e9..598348e13 100644 --- a/Xi/extinit.c +++ b/Xi/extinit.c @@ -74,6 +74,7 @@ SOFTWARE. /* modules local to Xi */ #include "allowev.h" +#include "chaccess.h" #include "chdevcur.h" #include "chgdctl.h" #include "chgfctl.h" @@ -94,12 +95,14 @@ SOFTWARE. #include "getselev.h" #include "getvers.h" #include "getvers.h" +#include "grabacc.h" #include "grabdev.h" #include "grabdevb.h" #include "grabdevk.h" #include "gtmotion.h" #include "listdev.h" #include "opendev.h" +#include "qryacces.c" #include "querydp.h" #include "queryst.h" #include "regpair.h" @@ -358,6 +361,12 @@ ProcIDispatch(register ClientPtr client) return (ProcXChangePointerKeyboardPairing(client)); else if (stuff->data == X_RegisterPairingClient) return (ProcXRegisterPairingClient(client)); + else if (stuff->data == X_GrabAccessControl) + return (ProcXGrabAccessControl(client)); + else if (stuff->data == X_ChangeWindowAccess) + return (ProcXChangeWindowAccess(client)); + else if (stuff->data == X_QueryWindowAccess) + return ProcXQueryWindowAccess(client); else { SendErrorToClient(client, IReqCode, stuff->data, 0, BadRequest); } @@ -457,6 +466,12 @@ SProcIDispatch(register ClientPtr client) return (SProcXChangePointerKeyboardPairing(client)); else if (stuff->data == X_RegisterPairingClient) return (SProcXRegisterPairingClient(client)); + else if (stuff->data == X_GrabAccessControl) + return (SProcXGrabAccessControl(client)); + else if (stuff->data == X_ChangeWindowAccess) + return (SProcXChangeWindowAccess(client)); + else if (stuff->data == X_QueryWindowAccess) + return SProcXQueryWindowAccess(client); else { SendErrorToClient(client, IReqCode, stuff->data, 0, BadRequest); } @@ -531,10 +546,16 @@ SReplyIDispatch(ClientPtr client, int len, xGrabDeviceReply * rep) (xChangeDeviceControlReply *) rep); else if (rep->RepType == X_QueryDevicePointer) SRepXQueryDevicePointer(client, len, - (xQueryDevicePointerReply *) rep); + (xQueryDevicePointerReply *) rep); else if (rep->RepType == X_RegisterPairingClient) SRepXRegisterPairingClient(client, len, - (xRegisterPairingClientReply *) rep); + (xRegisterPairingClientReply *) rep); + else if (rep->RepType == X_GrabAccessControl) + SRepXGrabAccessControl(client, len, + (xGrabAccessControlReply*) rep); + else if (rep->RepType == X_QueryWindowAccess) + SRepXQueryWindowAccess(client, len, + (xQueryWindowAccessReply*) rep); else { FatalError("XINPUT confused sending swapped reply"); } diff --git a/Xi/grabacc.c b/Xi/grabacc.c new file mode 100644 index 000000000..db9c9f2ca --- /dev/null +++ b/Xi/grabacc.c @@ -0,0 +1,102 @@ +/* + +Copyright 2007 Peter Hutterer + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +#define NEED_EVENTS +#define NEED_REPLIES +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include /* for inputstr.h */ +#include /* Request macro */ +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include "scrnintstr.h" /* screen structure */ +#include +#include +#include "extnsionst.h" +#include "extinit.h" /* LookupDeviceIntRec */ +#include "exevents.h" +#include "exglobals.h" + +#include "grabacc.h" + +/*********************************************************************** + * + * This procedure allows a client to register as the global client to control + * any window access. + * + */ +int +SProcXGrabAccessControl(ClientPtr client) +{ + char n; + REQUEST(xGrabAccessControlReq); + + swaps(&stuff->length, n); + return ProcXGrabAccessControl(client); +} + +int +ProcXGrabAccessControl(ClientPtr client) +{ + xGrabAccessControlReply rep; + REQUEST(xGrabAccessControlReq); + REQUEST_SIZE_MATCH(xGrabAccessControlReq); + + if (stuff->ungrab) + ACUnregisterClient(client); + + rep.repType = X_Reply; + rep.RepType = X_GrabAccessControl; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.success = stuff->ungrab || ACRegisterClient(client); + + WriteReplyToClient(client, sizeof(xGrabAccessControlReply), &rep); + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XGrabAccessControl function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGrabAccessControl(ClientPtr client, int size, + xGrabAccessControlReply* rep) +{ + register char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + WriteToClient(client, size, (char *)rep); +} + diff --git a/Xi/grabacc.h b/Xi/grabacc.h new file mode 100644 index 000000000..6dcbcad33 --- /dev/null +++ b/Xi/grabacc.h @@ -0,0 +1,41 @@ +/* + +Copyright 2007 Peter Hutterer + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef GRABACC_H +#define GRABACC_H 1 + +int SProcXGrabAccessControl(ClientPtr /* client */); + +int ProcXGrabAccessControl(ClientPtr /* client */); +void SRepXGrabAccessControl(ClientPtr client, int size, + xGrabAccessControlReply* rep); +#endif /* GRABACC_H */ diff --git a/Xi/qryacces.c b/Xi/qryacces.c new file mode 100644 index 000000000..817bec8a3 --- /dev/null +++ b/Xi/qryacces.c @@ -0,0 +1,128 @@ +/* + +Copyright 2007 Peter Hutterer + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +#define NEED_EVENTS +#define NEED_REPLIES +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include /* for inputstr.h */ +#include /* Request macro */ +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include "scrnintstr.h" /* screen structure */ +#include +#include +#include "extnsionst.h" +#include "extinit.h" /* LookupDeviceIntRec */ +#include "exevents.h" +#include "exglobals.h" + +#include "qryacces.h" + +/*********************************************************************** + * This procedure allows a client to query window access control. + */ + +int +SProcXQueryWindowAccess(ClientPtr client) +{ + char n; + REQUEST(xQueryWindowAccessReq); + + swaps(&stuff->length, n); + swapl(&stuff->win, n); + return ProcXQueryWindowAccess(client); +} + +int +ProcXQueryWindowAccess(ClientPtr client) +{ + int err; + WindowPtr win; + DeviceIntPtr *perm, *deny; + int nperm, ndeny, i; + int defaultRule; + CARD8* deviceids; + xQueryWindowAccessReply rep; + + REQUEST(xQueryWindowAccessReq); + REQUEST_SIZE_MATCH(xQueryWindowAccessReq); + + err = dixLookupWindow(&win, stuff->win, client, DixReadAccess); + if (err != Success) + { + SendErrorToClient(client, IReqCode, X_QueryWindowAccess, + stuff->win, err); + return Success; + } + + ACQueryWindowAccess(win, &defaultRule, &perm, &nperm, &deny, &ndeny); + + rep.repType = X_Reply; + rep.RepType = X_QueryWindowAccess; + rep.sequenceNumber = client->sequence; + rep.length = (nperm + ndeny + 3) >> 2; + rep.defaultRule = defaultRule; + rep.npermit = nperm; + rep.ndeny = ndeny; + WriteReplyToClient(client, sizeof(xQueryWindowAccessReply), &rep); + + if (nperm + ndeny) + { + deviceids = (CARD8*)xalloc((nperm + ndeny) * sizeof(CARD8)); + if (!deviceids) + { + ErrorF("ProcXQueryWindowAccess: xalloc failure.\n"); + SendErrorToClient(client, IReqCode, X_QueryWindowAccess, + 0, BadImplementation); + return Success; + } + + for (i = 0; i < nperm; i++) + deviceids[i] = perm[i]->id; + for (i = 0; i < ndeny; i++) + deviceids[i + nperm] = deny[i]->id; + + WriteToClient(client, nperm + ndeny, (char*)deviceids); + xfree(deviceids); + } + return Success; +} + +void +SRepXQueryWindowAccess(ClientPtr client, + int size, + xQueryWindowAccessReply* rep) +{ + char n; + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + WriteToClient(client, size, (char*)rep); +} diff --git a/Xi/qryacces.h b/Xi/qryacces.h new file mode 100644 index 000000000..5fce9aec2 --- /dev/null +++ b/Xi/qryacces.h @@ -0,0 +1,41 @@ +/* + +Copyright 2007 Peter Hutterer + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef QRYACCES_H +#define QRYACCES_H 1 + +int SProcXQueryWindowAccess(ClientPtr /* client */); +int ProcXQueryWindowAccess(ClientPtr /* client */); +void SRepXQueryWindowAccess(ClientPtr /* client */, + int /* size */, + xQueryWindowAccessReply* /* rep */); +#endif diff --git a/dix/Makefile.am b/dix/Makefile.am index a1f02c1b6..d9083ea52 100644 --- a/dix/Makefile.am +++ b/dix/Makefile.am @@ -5,6 +5,7 @@ AM_CFLAGS = $(DIX_CFLAGS) \ -DVENDOR_RELEASE="@VENDOR_RELEASE@" libdix_la_SOURCES = \ + access.c \ atom.c \ colormap.c \ cursor.c \ diff --git a/dix/access.c b/dix/access.c new file mode 100644 index 000000000..970d7c49a --- /dev/null +++ b/dix/access.c @@ -0,0 +1,287 @@ +/* + +Copyright 2007 Peter Hutterer + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +/* This file controls the access control lists for each window. + * Each device can be explicitely allowed or denied access to a given window. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include + +#include "input.h" +#include "inputstr.h" +#include "windowstr.h" + + +/* Only one single client can be responsible for window access control. */ +static ClientPtr ACClient = NULL; + + +/* Forward declarations */ +static void acReplaceList(DeviceIntPtr** list, + int* count, + DeviceIntPtr* devices, + int ndevices); + +/* Register global window access control client + * Return True on success or False otherwise. + */ + +Bool +ACRegisterClient(ClientPtr client) +{ + if (ACClient && ACClient != client) + return False; + + ACClient = client; + return True; +} + + +/* Unregister global client. If client is not the registered client, nothing + * happens and False is returned. If no client is registered, return True. + * Returns True if client was registred and is now unregistered. + */ + +Bool +ACUnregisterClient(ClientPtr client) +{ + if (ACClient && ACClient != client) + return False; + + ACClient = NULL; + return True; +} + +/* Clears all access control for the window and remove the default rule, + * depending on what is set. */ +int ACClearWindowAccess(ClientPtr client, + WindowPtr win, + int what) +{ + if (client != ACClient && client != wClient(win)) + return BadAccess; + + if (!win->optional) + { + /* we shouldn't get here if programmers know what they're doing. + * A client should not request to clear a window's access controls + * if they've never been set before anyway. If they do, do nothing and + * let the client figure out what to do next. + */ + return Success; + } + + if (what & WindowAccessClearPerm) + { + xfree(win->optional->access.perm); + win->optional->access.perm = NULL; + win->optional->access.nperm = 0; + } + + if (what & WindowAccessClearDeny) + { + xfree(win->optional->access.deny); + win->optional->access.deny = NULL; + win->optional->access.ndeny = 0; + } + + if (what & WindowAccessClearRule) + win->optional->access.defaultRule = WindowAccessNoRule; + + return Success; +} + +/* + * Changes window access control. + * + * Returns Success or BadAccess if the client is not allowed to change + * anything. + */ + +int +ACChangeWindowAccess(ClientPtr client, + WindowPtr win, + int defaultRule, + DeviceIntPtr* perm_devices, + int nperm, + DeviceIntPtr* deny_devices, + int ndeny) +{ + if (client != ACClient && client != wClient(win)) + return BadAccess; + + if (!win->optional && !MakeWindowOptional(win)) + { + ErrorF("ACChangeWindowAcccess: Failed to make window optional.\n"); + return BadImplementation; + } + + if (defaultRule != WindowAccessKeepRule) + win->optional->access.defaultRule = defaultRule; + + if (nperm) + { + acReplaceList(&win->optional->access.perm, + &win->optional->access.nperm, + perm_devices, nperm); + } + + if (ndeny) + { + acReplaceList(&win->optional->access.deny, + &win->optional->access.ndeny, + deny_devices, ndeny); + } + + return Success; +} + +static void +acReplaceList(DeviceIntPtr** list, + int* count, + DeviceIntPtr* devices, + int ndevices) +{ + xfree(*list); + *list = NULL; + *count = 0; + + if (ndevices) + { + *list = + xalloc(ndevices * sizeof(DeviceIntPtr*)); + if (!*list) + { + ErrorF("ACChangeWindowAccess: out of memory\n"); + return; + } + memcpy(*list, + devices, + ndevices * sizeof(DeviceIntPtr)); + *count = ndevices; + } + return; +} + +/* + * Query the given window for the devices allowed to access a window. + * The caller is responsible for freeing perm and deny. + */ +void +ACQueryWindowAccess(WindowPtr win, + int* defaultRule, + DeviceIntPtr** perm, + int* nperm, + DeviceIntPtr** deny, + int* ndeny) +{ + *defaultRule = WindowAccessNoRule; + *perm = NULL; + *nperm = 0; + *deny = NULL; + *ndeny = 0; + + if (!win->optional) + return; + + *defaultRule = win->optional->access.defaultRule; + + if (win->optional->access.nperm) + { + *nperm = win->optional->access.nperm; + *perm = (DeviceIntPtr*)xalloc(*nperm * sizeof(DeviceIntPtr)); + if (!*perm) + { + ErrorF("ACQuerywinAccess: xalloc failure\n"); + return; + } + memcpy(*perm, + win->optional->access.perm, + *nperm * sizeof(DeviceIntPtr)); + } + + if (win->optional->access.ndeny) + { + *ndeny = win->optional->access.ndeny; + *deny = (DeviceIntPtr*)xalloc(*ndeny * sizeof(DeviceIntPtr)); + if (!*deny) + { + ErrorF("ACQuerywinAccess: xalloc failure\n"); + return; + } + memcpy(*deny, + win->optional->access.deny, + *ndeny * sizeof(DeviceIntPtr)); + } +} + +/* + * Check if the given device is allowed to send events to the window. Returns + * true if device is allowed or false otherwise. + * + * Checks are done in the following order until a result is found: + * If the device is explicitely permitted, allow. + * If the window has a default of DenyAll, do not allow. + * If the device is explicitely denied, do not allow. + * Check parent window. Rinse, wash, repeat. + * If no rule could be found, allow. + */ +Bool +ACDeviceAllowed(WindowPtr win, DeviceIntPtr dev) +{ + int i; + + if (!win) /* happens for parent of RootWindow */ + return True; + + if (!win->optional) /* no list, check parent */ + return ACDeviceAllowed(win->parent, dev); + + for (i = 0; i < win->optional->access.nperm; i++) + { + if (win->optional->access.perm[i]->id == dev->id) + return True; + } + + if (win->optional->access.defaultRule == WindowAccessDenyAll) + return False; + + for (i = 0; i < win->optional->access.ndeny; i++) + { + if (win->optional->access.deny[i]->id == dev->id) + return False; + } + + return ACDeviceAllowed(win->parent, dev); +} + diff --git a/dix/dispatch.c b/dix/dispatch.c index a795d17a5..98183cc65 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -3568,6 +3568,7 @@ CloseDownClient(register ClientPtr client) DeleteClientFromAnySelections(client); ReleaseActiveGrabs(client); DeleteClientFontStuff(client); + ACUnregisterClient(client); UnregisterPairingClient(client); /* other clients can pair devices */ if (!really_close_down) { diff --git a/dix/events.c b/dix/events.c index 57a356db3..5ea9a65c2 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1663,6 +1663,9 @@ DeliverEventsToWindow(DeviceIntPtr pDev, register WindowPtr pWin, xEvent Mask deliveryMask = 0; /* If a grab occurs due to a button press, then this mask is the mask of the grab. */ int type = pEvents->u.u.type; + + if (!ACDeviceAllowed(pWin, pDev)) + return 0; /* CantBeFiltered means only window owner gets the event */ if ((filter == CantBeFiltered) || !(type & EXTENSION_EVENT_BASE)) @@ -2748,16 +2751,20 @@ DeliverGrabbedEvent(register xEvent *xE, register DeviceIntPtr thisDev, } if (!deliveries) { - FixUpEventFromWindow(thisDev, xE, grab->window, None, TRUE); - deliveries = TryClientEvents(rClient(grab), xE, count, - (Mask)grab->eventMask, - filters[xE->u.u.type], grab); - if (deliveries && (xE->u.u.type == MotionNotify + if (ACDeviceAllowed(grab->window, thisDev)) + { + + FixUpEventFromWindow(thisDev, xE, grab->window, None, TRUE); + deliveries = TryClientEvents(rClient(grab), xE, count, + (Mask)grab->eventMask, + filters[xE->u.u.type], grab); + if (deliveries && (xE->u.u.type == MotionNotify #ifdef XINPUT - || xE->u.u.type == DeviceMotionNotify + || xE->u.u.type == DeviceMotionNotify #endif - )) - thisDev->valuator->motionHintWindow = grab->window; + )) + thisDev->valuator->motionHintWindow = grab->window; + } } if (deliveries && !deactivateGrab && (xE->u.u.type != MotionNotify #ifdef XINPUT diff --git a/dix/window.c b/dix/window.c index 604af384d..3d7972812 100644 --- a/dix/window.c +++ b/dix/window.c @@ -452,6 +452,13 @@ CreateRootWindow(ScreenPtr pScreen) pWin->optional->inputMasks = NULL; pWin->optional->deviceCursors = NULL; #endif + + pWin->optional->access.perm = NULL; + pWin->optional->access.deny = NULL; + pWin->optional->access.nperm = 0; + pWin->optional->access.ndeny = 0; + pWin->optional->access.defaultRule = 0; + pWin->optional->colormap = pScreen->defColormap; pWin->optional->visual = pScreen->rootVisual; @@ -505,7 +512,6 @@ CreateRootWindow(ScreenPtr pScreen) if (disableSaveUnders) pScreen->saveUnderSupport = NotUseful; - return TRUE; } @@ -523,6 +529,7 @@ InitRootWindow(WindowPtr pWin) pWin->optional->cursor = rootCursor; rootCursor->refcnt++; + if (!blackRoot && !whiteRoot) { MakeRootTile(pWin); backFlag |= CWBackPixmap; @@ -3660,6 +3667,9 @@ CheckWindowOptionalNeed (register WindowPtr w) pNode = pNode->next; } } + if (optional->access.nperm != 0 || + optional->access.ndeny != 0) + return; parentOptional = FindWindowWithOptional(w)->optional; if (optional->visual != parentOptional->visual) @@ -3705,8 +3715,12 @@ MakeWindowOptional (register WindowPtr pWin) #endif #ifdef XINPUT optional->inputMasks = NULL; - optional->deviceCursors = NULL; #endif + optional->deviceCursors = NULL; + optional->access.nperm = 0; + optional->access.ndeny = 0; + optional->access.perm = NULL; + optional->access.deny = NULL; parentOptional = FindWindowWithOptional(pWin)->optional; optional->visual = parentOptional->visual; if (!pWin->cursorIsNone) @@ -3771,6 +3785,9 @@ DisposeWindowOptional (register WindowPtr pWin) pWin->optional->deviceCursors = NULL; } + xfree(pWin->optional->access.perm); + xfree(pWin->optional->access.deny); + xfree (pWin->optional); pWin->optional = NULL; } diff --git a/include/input.h b/include/input.h index d2e26efc1..a7b1e84d3 100644 --- a/include/input.h +++ b/include/input.h @@ -445,6 +445,37 @@ extern void SwitchCorePointer(DeviceIntPtr pDev); extern DeviceIntPtr LookupDeviceIntRec( CARD8 deviceid); +/* Pairing input devices */ +extern int PairDevices(ClientPtr client, + DeviceIntPtr pointer, + DeviceIntPtr keyboard); + +extern Bool RegisterPairingClient(ClientPtr client); +extern Bool UnregisterPairingClient(ClientPtr client); + +/* Window/device based access control */ +extern Bool ACRegisterClient(ClientPtr client); +extern Bool ACUnregisterClient(ClientPtr client); +extern int ACClearWindowAccess(ClientPtr client, + WindowPtr win, + int what); +extern int ACChangeWindowAccess(ClientPtr client, + WindowPtr win, + int defaultRule, + DeviceIntPtr* perm_devices, + int npermit, + DeviceIntPtr* deny_devices, + int ndeny); +extern void ACQueryWindowAccess(WindowPtr win, + int* defaultRule, + DeviceIntPtr** perm, + int* nperm, + DeviceIntPtr** deny, + int* ndeny); + +extern Bool ACDeviceAllowed(WindowPtr win, + DeviceIntPtr dev); + /* Implemented by the DDX. */ extern int NewInputDeviceRequest( InputOption *options); @@ -454,11 +485,4 @@ extern void DDXRingBell( int pitch, int duration); -extern int PairDevices(ClientPtr client, - DeviceIntPtr pointer, - DeviceIntPtr keyboard); - -extern Bool RegisterPairingClient(ClientPtr client); -extern Bool UnregisterPairingClient(ClientPtr client); - #endif /* INPUT_H */ diff --git a/include/windowstr.h b/include/windowstr.h index 4e9c82cb5..882f8a524 100644 --- a/include/windowstr.h +++ b/include/windowstr.h @@ -77,6 +77,14 @@ typedef struct _DevCursorNode { struct _DevCursorNode* next; } DevCursNodeRec, *DevCursNodePtr, *DevCursorList; +typedef struct _WindowAccessRec { + int defaultRule; /* WindowAccessDenyAll */ + DeviceIntPtr* perm; + int nperm; + DeviceIntPtr* deny; + int ndeny; +} WindowAccessRec, *WindowAccessPtr; + typedef struct _WindowOpt { VisualID visual; /* default: same as parent */ CursorPtr cursor; /* default: window.cursorNone */ @@ -97,6 +105,7 @@ typedef struct _WindowOpt { struct _OtherInputMasks *inputMasks; /* default: NULL */ #endif DevCursorList deviceCursors; /* default: NULL */ + WindowAccessRec access; } WindowOptRec, *WindowOptPtr; #define BackgroundPixel 2L