Xi: Add access control request handling.
dix: New file access.c to handle all access control for devices.
This commit is contained in:
committed by
Peter Hutterer
parent
cd0af7a785
commit
4b8b0e377a
287
dix/access.c
Normal file
287
dix/access.c
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
|
||||
Copyright 2007 Peter Hutterer <peter@cs.unisa.edu.au>
|
||||
|
||||
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 <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XI.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user