310 lines
13 KiB
XML
310 lines
13 KiB
XML
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
|
|
[
|
|
<!ENTITY % defs SYSTEM "defs.ent"> %defs;
|
|
]>
|
|
|
|
|
|
<!--translated from secint.tex, on 2010-06-27 15:38:00,
|
|
by TeX4ht (http://www.cse.ohio-state.edu/~gurari/TeX4ht/)
|
|
xhtml,docbook,html,refcaption -->
|
|
|
|
<book id="secint">
|
|
|
|
<bookinfo>
|
|
<title>Security Extension Server Design Draft</title>
|
|
<subtitle>X Consortium Standard</subtitle>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>David</firstname><othername>P.</othername><surname>Wiggins</surname>
|
|
<affiliation><orgname>X Consortium</orgname></affiliation>
|
|
</author>
|
|
</authorgroup>
|
|
<releaseinfo>X Version 11, Release &fullrelvers;</releaseinfo>
|
|
<releaseinfo>Version 3.0</releaseinfo>
|
|
<copyright><year>1996</year><holder>X Consortium</holder></copyright>
|
|
|
|
<legalnotice>
|
|
<para>
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
</para>
|
|
<para>
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
</para>
|
|
<para>
|
|
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 X CONSORTIUM 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.
|
|
</para>
|
|
<para>
|
|
Except as contained in this notice, the name of the X Consortium 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 X Consortium.
|
|
</para>
|
|
<para>X Window System is a trademark of The Open Group.</para>
|
|
</legalnotice>
|
|
<pubdate>June 27, 2010</pubdate>
|
|
|
|
<abstract>
|
|
<para>This paper describes the implementation strategy used to implement
|
|
various pieces of the SECURITY Extension.
|
|
</para>
|
|
</abstract>
|
|
|
|
</bookinfo>
|
|
|
|
|
|
<chapter id='Generate_Authorization_Request'>
|
|
<title>Generate Authorization Request</title>
|
|
|
|
<para>
|
|
The major steps taken to execute this request are as follows.
|
|
</para>
|
|
|
|
<para>
|
|
Sanity check arguments. The interesting one is the group, which must be
|
|
checked by some other module(s), initially just the embedding extension.
|
|
Use a new callback for this. The callback functions will be passed a small
|
|
structure containing the group ID and a Boolean value which is initially
|
|
false. If any of the callbacks recognize the ID, they should set the boolean
|
|
to true. If after the callbacks have been called the boolean is false, return
|
|
an error, since nobody recognized it.
|
|
</para>
|
|
|
|
<para>
|
|
Use the existing Xkey library function XkeyGenerateAuthorization to generate
|
|
the new authorization.
|
|
</para>
|
|
|
|
<para>
|
|
Use the existing os layer function AddAuthorization to add the new
|
|
authorization to the server's internal database.
|
|
</para>
|
|
|
|
<para>
|
|
Use the existing os layer function AuthorizationToID to retrieve
|
|
the authorization ID that the os layer assigned to the new authorization.
|
|
</para>
|
|
|
|
<para>Change the os layer to use authorization IDs allocated from the
|
|
server's ID range via FakeClientID(0) instead of using a simple incrementing
|
|
integer. This lets us use the resource database to attach additional
|
|
information to an authorization without needing any changes to os
|
|
data structures.
|
|
</para>
|
|
|
|
<para>
|
|
Add the authorization ID as a server resource. The structure for an
|
|
authorization resource will contain the timeout, trust-level, and group
|
|
sent in the request, a reference count of how many clients are connected
|
|
with this authorization, a timer pointer, and time-remaining counter.
|
|
</para>
|
|
|
|
<para>
|
|
Return the authorization ID and generated auth data to the client.
|
|
</para>
|
|
|
|
</chapter>
|
|
<chapter id='Client_Connection'>
|
|
<title>Client Connection</title>
|
|
|
|
<para>
|
|
The Security extension needs to be aware of new client connections
|
|
primarily so that it copy the trust-level of the authorization that was
|
|
used to the client structure. The trust-level is needed in the client
|
|
structure because it will be accessed frequently to make access control
|
|
decisions for the client. We will use the existing ClientStateCallback
|
|
to catch new client connections.
|
|
</para>
|
|
|
|
<para>
|
|
We also need to copy the authorization ID into the client structure. The
|
|
authorization ID is already stored in an os private hung from the client,
|
|
and we will add a new os function AuthorizationIDOfClient to retrieve it.
|
|
However, when a client disconnects, this os private is already gone before
|
|
ClientStateCallbacks are called. We need the authorization ID at client
|
|
disconnect time for reasons described below.
|
|
</para>
|
|
|
|
<para>
|
|
Now that we know what needs to be done and why, let's walk through the
|
|
sequence of events.
|
|
</para>
|
|
|
|
<para>
|
|
When a new client connects, get the authorization ID with
|
|
AuthorizationIDOfClient, store it in the client, then pass that ID to
|
|
LookupIDByType to find the authorization. If we get a non-NULL pointer
|
|
back, this is a generated authorization, not one of the predefined ones in
|
|
the server's authority file. In this case, increment the authorization's
|
|
reference count. If the reference count is now 1, cancel the timer
|
|
for this authorization using the trivial new os layer function TimerCancel.
|
|
Lastly, copy the trust-level of this authorization into the client structure
|
|
so that it can be reached quickly for future access control decisions.
|
|
</para>
|
|
|
|
<para>
|
|
The embedding extension can determine the group to use for a new client in
|
|
the same way that we determined the trust level: get the authorization ID,
|
|
look it up, and if that succeeds, pluck the group out of the returned
|
|
authorization structure.
|
|
</para>
|
|
</chapter>
|
|
|
|
<chapter id='Client_disconnection'>
|
|
<title>Client disconnection</title>
|
|
|
|
<para>
|
|
Use the existing ClientStateCallback to catch client disconnections. If the
|
|
client was using a generated authorization, decrement its reference count.
|
|
If the reference count is now zero, use the existing os layer function
|
|
TimerSet to start a timer to count down the timeout period for this
|
|
authorization. Record the timer ID for this authorization. When the timer
|
|
fires, the authorization should be freed, removing all
|
|
traces of it from the server.
|
|
</para>
|
|
|
|
<para>
|
|
There is a slight complication regarding the timeout because the timer
|
|
interface in the server allows for 32 bits worth of milliseconds, while
|
|
the timeout specified in GenerateAuthorization has 32 bits worth of seconds.
|
|
To handle this, if the specified time is more than the timer interface can
|
|
handle, the maximum possible timeout will be set, and time-remaining counter
|
|
for this authorization will be used to track the leftover part. When the
|
|
timer fires, it should first check to see if there is any leftover
|
|
time to wait. If there is, it should set another timer to the minimum of (the
|
|
maximum possible timeout) and the time remaining, and not do the revocation
|
|
yet.
|
|
</para>
|
|
</chapter>
|
|
|
|
<chapter id='Resource_ID_Security'>
|
|
<title>Resource ID Security</title>
|
|
|
|
<para>
|
|
To implement the restriction that untrusted clients cannot access resources
|
|
of trusted clients, we add two new functions to dix: SecurityLookupIDByType
|
|
and SecurityLookupIDByClass. Hereafter we will use SecurityLookupID to refer
|
|
to both functions. In addition to the parameters of the existing LookupID
|
|
functions, these functions also take a pointer to the client doing the lookup,
|
|
and an access mode that conveys a high-level idea of what the client intends
|
|
to do with the resource (currently just read, write, destroy, and unknown).
|
|
Passing NullClient for the client turns off access checks. SecurityLookupID can
|
|
return NULL for two reasons: the resource doesn't exist, or it does but the
|
|
client isn't allowed to access it. The caller cannot tell the difference. Most
|
|
places in dix call these new lookup functions instead of the old LookupID,
|
|
which continue to do no access checking. Extension "Proc" functions should
|
|
probably use SecurityLookupID, not LookupID. Ddxen can continue to use
|
|
LookupID.
|
|
</para>
|
|
|
|
<para>
|
|
Inside SecurityLookupID, the function client -> CheckAccess is called
|
|
passing the client, resource id, resource type/class, resource value, and
|
|
access mode. CheckAccess returns the resource value if access is allowed,
|
|
else it returns NULL. The entire resource ID security policy of the Security
|
|
extension can be replaced by plugging in your own access decision function
|
|
here. This in combination with the access mode parameter should be enough to
|
|
implement a more traditional DAC (discretionary access control) policy.
|
|
</para>
|
|
|
|
<para>
|
|
Since we need client and access mode information to do access controlled
|
|
resource lookups, we add (and use) several other macros and functions that
|
|
parallel existing ones with the addition of the missing information. The list
|
|
includes SECURITY_VERIFY_GC, SECURITY_VERIFY_DRAWABLE,
|
|
SECURITY_VERIFY_GEOMETRABLE, SecurityLookupWindow,
|
|
SecurityLookupDrawable, and dixChangeGC. The dixChangeGC interface is
|
|
worth mentioning because in addition to a client parameter, we introduce a
|
|
pointer-to-union parameter that should let us eliminate the warnings that some
|
|
compilers give when you assign small integers to pointers, as the DoChangeGC
|
|
interface required. For more details, see the comment preceding dixChangeGC in
|
|
;<dix/gc.c;>.
|
|
</para>
|
|
|
|
<para>
|
|
If XCSECURITY is not defined (the Security extension is not being built),
|
|
the server uses essentially the same code as before for resource lookups.
|
|
</para>
|
|
|
|
</chapter>
|
|
<chapter id='Extension_Security'>
|
|
<title>Extension Security</title>
|
|
|
|
<para>
|
|
A new field in the ExtensionEntry structure, Bool secure, tells whether the
|
|
extension is considered secure. It is initialized to FALSE by AddExtension.
|
|
The following new dix function can be used to set the secure field:
|
|
</para>
|
|
|
|
<funcsynopsis id='DeclareExtensionSecurity'>
|
|
<funcprototype>
|
|
<funcdef>void <function>DeclareExtensionSecurity</function></funcdef>
|
|
<paramdef>char <parameter> *extname</parameter></paramdef>
|
|
<paramdef>Bool <parameter>secure</parameter></paramdef>
|
|
</funcprototype>
|
|
</funcsynopsis>
|
|
|
|
<para>
|
|
The name of the extension and the desired value of the secure field are
|
|
passed. If an extension is secure, a call to this function with
|
|
secure = TRUE will typically appear right after the call to
|
|
<function>AddExtension</function>.
|
|
<xref linkend='DeclareExtensionSecurity' xrefstyle='select: title'/>
|
|
should be called during server reset. It should not
|
|
be called after the first client has connected. Passing the name of an
|
|
extension that has not been initialized has no effect (the secure value will
|
|
not be remembered in case the extension is later initialized).
|
|
</para>
|
|
|
|
<para>
|
|
For untrusted clients, <function>ProcListExtensions</function> omits
|
|
extensions that have secure = FALSE, and
|
|
<function>ProcQueryExtension</function> reports that such
|
|
extensions don't exist.
|
|
</para>
|
|
|
|
<para>
|
|
To prevent untrusted clients from using extensions by guessing their major
|
|
opcode, one of two new Proc vectors are used by untrusted clients,
|
|
<function>UntrusedProcVector</function> and
|
|
<function>SwappedUntrustedProcVector</function>. These have the same contents
|
|
as <function>ProcVector</function> and
|
|
<function>SwappedProcVector</function> respectively for the first 128
|
|
entries. Entries 128 through 255 are initialized to ProcBadRequest. If
|
|
<xref linkend='DeclareExtensionSecurity' xrefstyle='select: title'/> is called with secure =
|
|
TRUE, that extension's dispatch function is plugged into the appropriate entry
|
|
so that the extension can be used. If
|
|
<xref linkend='DeclareExtensionSecurity' xrefstyle='select: title'/> is called with secure =
|
|
FALSE, the appropriate entry is reset to ProcBadRequest.
|
|
</para>
|
|
|
|
<para>
|
|
Now we can explain why <xref linkend='DeclareExtensionSecurity' xrefstyle='select: title'/>
|
|
should not be called after the first client connects. In some cases,
|
|
the Record extension gives clients a private copy of the proc vector,
|
|
which it then changes to intercept certain requests. Changing entries in
|
|
<function>UntrusedProcVector</function> and
|
|
<function>SwappedUntrustedProcVector</function> will have no effect on these
|
|
copied proc vectors. If we get to the point of needing an extension request
|
|
to control which extensions are secure, we'll need to invent a way to
|
|
get those copied proc vectors changed.
|
|
</para>
|
|
</chapter>
|
|
</book>
|
|
|
|
|