tsolprotocol.c revision 98
/* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
*
* 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,
* to whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* 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
* OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
* INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Except as contained in this notice, the name of a copyright holder
* shall not be used in advertising or otherwise to promote the sale, use
* or other dealings in this Software without prior written authorization
* of the copyright holder.
*/
#pragma ident "@(#)tsolprotocol.c 1.16 07/01/24 SMI"
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <ucred.h>
#include <pwd.h>
#include <strings.h>
#include <bsm/auditwrite.h>
#include <bsm/audit_uevents.h>
#include "tsol.h"
#include "inputstr.h"
#define NEED_REPLIES
#include "selection.h"
#include "osdep.h"
#include "tsolpolicy.h"
#include "swaprep.h"
#include "swapreq.h"
#include "servermd.h"
#ifdef PANORAMIX
#include "../Xext/panoramiXsrv.h"
#endif
#ifdef XCSECURITY
#define _SECURITY_SERVER
#include "security.h"
#endif
/*
* The event # here match those in /usr/include/bsm/audit_uevents.h.
* Changes in one should go with corresponding changes in another.
*/
#define MAX_AUDIT_EVENTS 100
};
extern void Swap32Write();
#define INITIAL_TSOL_NODELENGTH 1500
extern WindowPtr XYToWindow(int x, int y);
extern Atom tsol_lastAtom;
extern int tsol_nodelength;
extern TsolNodePtr tsol_node;
extern int NumCurrentSelections;
extern Selection *CurrentSelections;
extern int tsolMultiLevel;
/*
* Get number of atoms defined in the system
*/
static Atom
{
while (ValidAtom(a)) {
a++;
}
return (--a);
}
/*
* Update Tsol info for atoms. This function gets
* called typically during initialization. But, it could also get
* called if some atoms are created internally by server.
*/
void
{
/* Update may not be needed */
return;
/* Initialize */
/* Atom id 0 is invalid */
tsol_lastAtom = 0;
}
}
if (tsol_nodelength <= lastAtom) {
}
ErrorF("Cannot allocate memory for Tsol node\n");
return;
}
/*
* Initialize the tsol node for each atom
*/
}
}
int
{
char *tchar;
{
return(BadValue);
}
if (atom != BAD_RESOURCE)
{
return(client->noClientException);
}
else
return (BadAlloc);
}
int
{
char *str;
int len;
/* TBD: NameForTSOLAtom */
{
return(client->noClientException);
}
else
{
return (BadAtom);
}
}
{
int count;
int k;
int newsize;
/* Make the atom as usual */
return (newAtom);
}
/* tsol node info already present? */
if (newAtom <= tsol_lastAtom) {
/* public atoms have null sl */
return newAtom;
}
/* private atoms must have a matching sl */
return newAtom; /* found one */
}
}
} else {
/* tsol node table not big enough, expand it */
}
/* Allocate storage for sl if needed */
}
/* Expand storage space for sl if needed */
}
ErrorF("Not enough memory for atoms\n");
}
/* Store client's sl */
return newAtom;
}
int
{
#ifdef TSOL
#endif /* TSOL */
/* If the client's time stamp is in the future relative to the server's
time stamp, do not set the selection, just return success. */
return Success;
{
if (!pWin)
return(BadWindow);
}
else
{
int i = 0;
/*
* First, see if the selection is already set...
*/
while ((i < NumCurrentSelections) &&
i++;
#ifdef TSOL
/*
* special processing for selection agent. Just note
* the owner of this special selection
*/
{
if (HasWinSelection(tsolinfo))
{
tsol_sel_agnt = i; /* owner of this seln */
}
else
{
return(BadAtom);
}
}
#endif /* TSOL */
if (i < NumCurrentSelections)
{
#ifdef TSOL
/* for poly-selections, search further to see if sl,uid match */
{
while (tsolseln)
{
break; /* match found */
}
}
{
return Success;
{
&event,
1,
NoEventMask /* CantBeFiltered */,
NullGrab);
}
}
else if (tsolseln)
{
/* we use the existing code. So we left it unindented */
#endif /* TSOL */
/* If the timestamp in client's request is in the past relative
to the time stamp indicating the last time the owner of the
selection was set, do not set the selection, just return
success. */
== EARLIER)
return Success;
if (CurrentSelections[i].client &&
{
NullGrab);
}
#ifdef TSOL
}
#endif /* TSOL */
}
else
{
/*
* It doesn't exist, so add it...
*/
if (i == 0)
else
if (!newsels)
return BadAlloc;
}
#ifdef TSOL
/*
* tsolseln == NULL, either seln does not exist,
* or there is no sl,uid match
*/
if (!tsolseln)
{
/* create one & put it in place */
if (!tsolseln)
return BadAlloc;
/* if necessary put at the end of the list */
if (prevtsolseln)
else
}
/* fill it in */
{
/* no change to existing code. left as it is */
#endif /* TSOL */
if (SelectionCallback)
{
}
#ifdef TSOL
}
#endif /* TSOL */
return (client->noClientException);
}
else
{
return (BadAtom);
}
}
int
{
{
int i;
i = 0;
while ((i < NumCurrentSelections) &&
if (i < NumCurrentSelections)
#ifdef TSOL
{
/* find matching sl,uid in case of poly selns */
{
while (tsolseln)
{
break; /* match found */
}
if (tsolseln)
else
}
else
{
}
/*
* Selection Agent processing. Override the owner
*/
if (!HasWinSelection(tsolinfo) &&
tsol_sel_agnt != -1 &&
{
}
else if (HasWinSelection(tsolinfo) &&
{
}
/* end seln agent processing */
}
#else /* TSOL */
#endif /* TSOL */
else
return(client->noClientException);
}
else
{
return (BadAtom);
}
}
int
{
if (!pWin)
return(BadWindow);
if (paramsOkay)
{
int i;
i = 0;
while ((i < NumCurrentSelections) &&
#ifdef TSOL
if (i < NumCurrentSelections)
{
/* find matching sl,uid in case of poly selns */
{
while (tsolseln)
{
break; /* match found */
}
if (!tsolseln)
{
return (BadAtom);
}
}
else
{
}
/*
* Special case for seln agent.
* SelectionRequest event is redirected to selection
* agent for unpirvileged clients and who do not own
* the selection
*/
{
/* Redirect only if client other than owner & does not have priv */
{
}
else if (HasWinSelection(tsolinfo) &&
{
}
}
/* end of special case seln handling */
{
NullGrab))
return (client->noClientException);
}
}
#else /* TSOL */
if ((i < NumCurrentSelections) &&
#ifdef XCSECURITY
&& (!client->CheckAccess ||
CurrentSelections[i].pWin))
#endif
)
{
if (TryClientEvents(
return (client->noClientException);
}
#endif /* TSOL */
return (client->noClientException);
}
else
{
return (BadAtom);
}
}
/* Allocate and initialize a tsolprop */
{
if (tsolprop)
{
}
return tsolprop;
}
/*
* instantiated properties. Polyinstanticated property
*/
int
unsigned long len;
{
int sizeInBytes;
int totalSize;
int result;
if (!polyprop)
{
return (result);
}
/* first see if property already exists */
while (pProp )
{
break;
}
/* Initialize secPrviate if property is not polyinstantiated */
{
/* Initialize for internally created properties */
if (!pProp->secPrivate)
if (!pProp->secPrivate)
return(BadAlloc);
if (WindowIsRoot(pWin))
{
}
else
{
}
return (result);
}
/* Handle polyinstantiated property */
if (!pProp) /* just add to list */
{
return(BadAlloc);
if (!pProp)
return(BadAlloc);
if (!pProp->secPrivate)
return(BadAlloc);
{
return(BadAlloc);
}
if (len)
if (WindowIsRoot(pWin))
{
}
else
{
}
} /* end if !prop */
else
{
/* To append or prepend to a property the request format and type
* must match those of the already defined property. The
* existing format and type are irrelevant when using the mode
* "PropModeReplace" since they will be written over.
*/
return(BadMatch);
return(BadMatch);
/* search for a matching (sl, uid) pair */
while (tsolprop)
{
break; /* match found */
}
if (!tsolprop)
{
/* no match found. Create one */
if (!newtsol)
return(BadAlloc);
{
return(BadAlloc);
}
if (len)
}
else
{
switch (mode)
{
case PropModeReplace:
{
return(BadAlloc);
}
if (len)
break;
case PropModeAppend:
if (len)
{
data =
if (!data)
return(BadAlloc);
}
break;
case PropModePrepend:
if (len)
{
data =
if (!data)
return(BadAlloc);
}
break;
}
}
} /* end else if !prop */
return(Success);
}
int
{
if (client == serverClient)
{
}
else
{
}
return (Success);
}
int
{
return(Success);
while (pProp)
{
{
/* Found a matching name. Further match for SL,UID */
while (tsolprop)
{
if (tsolpolyinstinfo.enabled)
{
{
break;
}
}
else
{
{
break;
}
}
}
break;
}
}
if (pProp)
{
if (tsolprop)
{
if (prevtsolprop)
{
}
}
}
return(Success);
}
int
{
int numProps = 0;
int err_code;
if (!pWin)
return(BadWindow);
/* policy check for window */
{
return (err_code);
}
while (pProp)
{
{
numProps++;
}
else
{
/* error ignored */
numProps++;
}
}
if (numProps)
return(BadAlloc);
temppAtoms = pAtoms;
while (pProp)
{
{
}
else
{
/* error ignored */
}
}
if (numProps)
{
}
return(client->noClientException);
}
int
{
int err_code;
if (!pWin)
return BadWindow;
{
return(BadAtom);
}
{
return(BadValue);
}
{
return(BadAtom);
}
/* policy check for window */
{
return (err_code);
}
{
}
while (pProp)
{
{
while (tsolprop)
{
if (tsolpolyinstinfo.enabled)
{
break;
}
else
{
break; /* match found */
}
}
break;
}
}
{
reply.bytesAfter = 0;
}
else
{
/* If the request type and actual type don't match. Return the
property information, but not the data. */
{
return(Success);
}
/*
* Return type, format, value to client
*/
/* If longOffset is invalid such that it causes "len" to
be negative, it's a value error. */
if (n < ind)
{
return BadValue;
}
/* policy check for delete error ignored */
{ /* send the event */
}
if (len)
{
}
}
{ /* delete the Property */
{
}
else
/* remove the tsol struct */
/* delete the prop for last reference */
if (tsolprop == prevtsolprop)
}
}
return (client->noClientException);
}
int
{
int status;
{
}
else
{
}
return (status);
}
int
{
int status;
{
}
else
{
}
return (status);
}
int
{
int status;
{
}
else
{
}
return (status);
}
int
{
int status;
{
}
else
{
}
return (status);
}
int
{
int status;
{
}
else
{
}
return (status);
}
int
{
int inputMapLen;
register int i;
int status;
(sizeof (xSetModifierMappingReq)>>2)))
return BadLength;
/*
* Now enforce the restriction that "all of the non-zero keycodes must be
* in the range specified by min-keycode and max-keycode in the
* connection setup (else a Value error)"
*/
i = inputMapLen;
while (i--)
{
if (inputMap[i]
{
return BadValue;
}
}
{
/*
* silently ignore the request. xview apps
* complain if we return error code. If we don't
* send the map notify event application hangs
*/
}
else
{
}
return (status);
}
void
{
if (!tpwin)
return;
}
}
}
static void
{
/* Validate trusted stripe window */
if (tpwin)
return;
/* stripe is already at head, nothing to do */
return;
}
int
{
int result;
return BadWindow;
return (result);
/* Initialize tsol security attributes */
/* stuff tsol info into window from client */
/* Client is Server itself */
}
else
{
}
else
return result;
}
int
{
int result;
if (!pWin)
return(BadWindow);
{
if (!WindowIsRoot(pWin))
return (result);
}
return result;
}
int
{
int result;
return result;
}
int
{
int result;
return result;
}
int
{
int result;
return result;
}
int
{
if (!pWin)
return BadWindow;
return Success; /* ignore error */
}
/*
* HandleHotKey -
* HotKey is Meta(Diamond)+ Stop Key
* Breaks untusted Ptr and Kbd grabs.
* Trusted Grabs are NOT broken
* Warps pointer to the Trusted Stripe if not Trusted grabs in force.
*/
void
{
extern unsigned int StripeHeight;
int x, y;
if (kbdgrab)
{
if (tsolinfo)
{
if (HasTrustedPath(tsolinfo))
trusted_grab = TRUE;
else
}
if (ptrgrab)
{
if (tsolinfo)
{
if (HasTrustedPath(tsolinfo))
trusted_grab = TRUE;
else
}
}
}
if (!trusted_grab)
{
/*
* Warp the pointer to the Trusted Stripe
*/
}
}
int
{
{
if ((focuswin != NullWindow) &&
{
return (client->noClientException);
}
}
}
int
{
#ifdef PANORAMIX
if ( !noPanoramiXExtension )
return PanoramiXGetInputFocus(client);
#endif
return Success;
}
void
{
while (p2)
{
}
}
/*
* Checks that tpwin & its siblings have same
* parents. Returns 0 if OK, a # indicating which
* Sibling has a bad parent
*/
int
{
int count = 1;
while (pWin)
{
return count;
++count;
}
return 0;
}
/* NEW */
int
{
int status;
return status;
/* Reduce root window height = stripe height */
{
extern unsigned int StripeHeight;
}
return(client->noClientException);
}
int
{
{
/* turn off auditing because operation ignored */
return(client->noClientException);
}
}
int
{
{
/* turn off auditing because operation ignored */
return(client->noClientException);
}
}
int
{
int result;
if (pMap)
{
/* Initialize security info */
{
/* Client is Server itself */
}
else
{
}
}
return result;
}
int
{
int result;
return (result);
}
int
{
int result;
return (result);
return (result);
}
int
{
int result;
{
return (result);
}
return (result);
}
int
{
int result;
{
return (result);
}
}
int
{
{
return (BadValue);
}
}
int
{
}
{
int result;
return (result);
}
void
{
register int i;
for (i = 0; i< NumCurrentSelections; i++)
{
{
while (tsolseln)
{
break; /* match found */
}
if (tsolseln)
{
if (SelectionCallback)
{
}
/* first on the list */
if (prevtsolseln == tsolseln)
else
/* handle the last reference */
{
}
}
}
else
{
{
}
}
}
}
void
{
register int i;
for (i = 0; i< NumCurrentSelections; i++)
{
{
while (tsolseln)
{
break; /* match found */
}
if (tsolseln)
{
if (SelectionCallback)
{
}
/* first on the list */
if (prevtsolseln == tsolseln)
else
/* handle the last reference */
{
}
}
}
else
{
{
}
}
}
}
int
{
int nummaps;
if (!pWin)
return(BadWindow);
ALLOCATE_LOCAL(sizeof(xListInstalledColormapsReply) +
sizeof(Colormap));
if(!preply)
return(BadAlloc);
#ifdef TSOL
{
int err_code, i;
/*
* check every colormap id for access. return default colormap
* id in case of failure
*/
{
{
}
}
}
#endif /* TSOL */
return(client->noClientException);
}
int
{
int numChildren = 0;
int j, thisScreen;
#endif
#ifdef TSOL
#endif /* TSOL */
if (!pWin)
return(BadWindow);
#ifdef TSOL
{
return(BadWindow);
}
/*
* Because of its recursive nature, QuerryTree can leave a huge trail
* of audit records which could make deciphering the audit log for
* critical records difficult. So we turn off any more auditing of
* this protocol.
*/
#endif /* TSOL */
else
if ( !noPanoramiXExtension ) {
thisScreen = 0;
for (j = 0; j <= PanoramiXNumScreens - 1; j++) {
panoramiXdataPtr[j].width)) {
thisScreen = j;
break;
}
}
}
if ( !noPanoramiXExtension && thisScreen ) {
pWin =
if (!pWin)
return(BadWindow);
numChildren++;
if (numChildren)
{
int curChild = 0;
if (!childIDs)
return BadAlloc;
}
} /* numChildren */
}else { /* otherwise its screen 0, and nothing changes */
#ifdef TSOL
{
/* error ignored */
{
numChildren++;
}
}
#else /* !TSOL */
numChildren++;
#endif /* TSOL */
if (numChildren)
{
int curChild = 0;
if (!childIDs)
return BadAlloc;
#ifdef TSOL
{
/* error ignored */
{
}
}
#else /* !TSOL */
#endif /* TSOL */
}
}
#else
#ifdef TSOL
{
/* error ignored */
{
numChildren++;
}
}
#else /* !TSOL */
numChildren++;
#endif /* TSOL */
if (numChildren)
{
int curChild = 0;
if (!childIDs)
return BadAlloc;
#ifdef TSOL
{
/* error ignored */
{
}
}
#else /* !TSOL */
#endif /* TSOL */
}
#endif
if (numChildren)
{
}
return(client->noClientException);
}
void
{
extern Bool system_audit_on;
unsigned int protocol;
int xevent_num;
int count = 0;
int status = 0;
if (system_audit_on &&
do_x_audit = TRUE;
/*
* X audit events start from 9101 in audit_uevents.h. The first two
* events are non-protocol ones viz. ClientConnect, mapped to 9101
* and ClientDisconnect, mapped to 9102.
* The protocol events are mapped from 9103 onwards in the serial
* order of their respective protocol opcode, for eg, the protocol
* UngrabPointer which is has a protocol opcode 27 is mapped to
* 9129 (9102 + 27).
* All extension protocols are mapped to a single audit event
* AUE_XExtension as opcodes are assigined dynamically to these
* protocols. We set the extension protocol opcode to be 128, one
* more than the last standard opcode.
*/
if (protocol > X_NoOperation) {
audit_event = TRUE;
} else {
audit_event = TRUE;
break;
}
}
}
/*
* Exclude Clients with Trusted Path such as tsoldtwm, tsoldtsession etc
* from generating the audit records for X protocols
*/
AU_PRS_USECACHE) == 1)) {
} else {
}
}
}
void
{
extern Bool system_audit_on;
unsigned int protocol;
int xevent_num;
int count = 0;
int status = 0;
{
audit_ret = -1;
else
audit_ret = 0;
}
{
}
}
int
{
if (!pWin)
return BadWindow;
ptrWin = TsolPointerWindow();
return(Success);
}
int
{
int savedtrust;
reply.major_opcode = 0;
/* Allow extensions in the labeled zones */
} else {
/* Hide this extension */
}
return (status);
}
int
{
int savedtrust;
int status;
/* Allow extensions in the labeled zones */
return (status);
}
int
{
int savedtrust;
if (!pWin)
return(BadWindow);
return(client->noClientException);
}
int
{
int savedtrust;
if (!pWin)
return(BadWindow);
return(client->noClientException);
}
static int
int format;
{
register DrawablePtr pDraw;
int nlines, linesPerBuf;
register int linesDone;
long widthBytesLine, length;
char *pBuf;
#ifdef TSOL
#endif /* TSOL */
{
return(BadValue);
}
#ifdef TSOL
{
}
{
if (DrawableIsRoot(pDraw))
{
pWin = XYToWindow(x, y);
if (!WindowIsRoot(pWin))
{
{
/* requested area must be a subset of the window area */
{
x = tmpx;
y = tmpy;
}
}
}
}
else
{
}
if (not_root_window)
{
while (tmpwin)
{
{
break;
}
}
}
getimage_ok = FALSE;
else
getimage_ok = TRUE;
}
#endif /* TSOL */
{
if( /* check for being viewable */
/* check for being on screen */
pDraw->x + x < 0 ||
pDraw->y + y < 0 ||
/* check for being inside of border */
)
return(BadMatch);
}
else
{
if(x < 0 ||
y < 0 ||
)
return(BadMatch);
}
{
}
else
{
/* only planes asked for */
}
if (im_return) {
if (!pBuf)
return (BadAlloc);
if (widthBytesLine == 0)
linesPerBuf = 0;
else
} else {
if (widthBytesLine == 0 || height == 0)
linesPerBuf = 0;
else if (widthBytesLine >= IMAGE_BUFSIZE)
linesPerBuf = 1;
else
{
if (linesPerBuf > height)
}
if (linesPerBuf < height)
{
/* we have to make sure intermediate buffers don't need padding */
while ((linesPerBuf > 1) &&
{
linesPerBuf--;
length -= widthBytesLine;
}
{
linesPerBuf++;
length += widthBytesLine;
}
}
return (BadAlloc);
}
if (linesPerBuf == 0)
{
/* nothing to do */
}
{
linesDone = 0;
{
x,
y + linesDone,
#ifdef TSOL
if (not_root_window)
{
if (over_win &&
{
}
}
/*
* fill the buffer with zeros in case of security failure
*/
if (!getimage_ok || overlap)
{
if (overlap)
}
#endif /* TSOL */
/* Note that this is NOT a call to WriteSwappedDataToClient,
as we do NOT byte swap */
if (!im_return)
{
/* Don't split me, gcc pukes when you do */
(void)WriteToClient(client,
(int)(nlines * widthBytesLine),
pBuf);
}
}
}
else /* XYPixmap */
{
{
{
linesDone = 0;
{
x,
y + linesDone,
#ifdef TSOL
if (not_root_window)
{
if (over_win &&
{
}
}
/*
* fill the buffer with zeros in case of security failure
*/
if (!getimage_ok || overlap)
{
if (overlap)
}
#endif /* TSOL */
/* Note: NOT a call to WriteSwappedDataToClient,
as we do NOT byte swap */
if (im_return) {
} else {
/* Don't split me, gcc pukes when you do */
(void)WriteToClient(client,
(int)(nlines * widthBytesLine),
pBuf);
}
}
}
}
}
if (!im_return)
return (client->noClientException);
}
int
{
int status;
return (status);
}
int
{
int savedtrust;
int status;
{
/* ignore the error message for DnD zap effect */
return (client->noClientException);
}
{
return (BadGC);
}
return (status);
}
int
{
int savedtrust;
int status;
{
/* ignore the error message */
return (client->noClientException);
}
{
return (BadGC);
}
return (status);
}
int
{
int savedtrust;
int status;
register DrawablePtr pDst;
register DrawablePtr pSrc;
{
{
return (BadMatch);
}
}
else
{
/* ignore the error message for DnD zap effect */
return(client->noClientException);
}
{
/* ignore the error message for DnD zap effect */
return(client->noClientException);
}
{
return (BadGC);
}
return (status);
}
int
{
int savedtrust;
int status;
{
{
return (BadMatch);
}
}
else
{
/* ignore the error message for DnD zap effect */
return(client->noClientException);
}
{
/* ignore the error message for DnD zap effect */
return(client->noClientException);
}
{
return (BadGC);
}
return (status);
}