tsolextension.c revision 667
/* Copyright 2009 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 "@(#)tsolextension.c 1.36 09/03/12 SMI"
#include <stdio.h>
#include "auditwrite.h"
#include <bsm/audit_uevents.h>
#include <ucred.h>
#include <netdb.h>
#include <strings.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <zone.h>
#define NEED_REPLIES
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "misc.h"
#include "osdep.h"
#include "tsol.h"
#include "inputstr.h"
#include "extnsionst.h"
#include "dixstruct.h"
#include "xace.h"
#include "xacestr.h"
#ifdef PANORAMIX
#include "../Xext/panoramiXsrv.h"
#endif
#ifdef XCSECURITY
#define _SECURITY_SERVER
#include "security.h"
#include "../Xext/securitysrv.h"
#endif
#include "tsolpolicy.h"
#define BadCmapCookie 0
#define EXTNSIZE 128
#define SECURE_RPC_AUTH "SUN-DES-1"
#define SECURE_RPC_LEN 9
static int ProcTsolDispatch(ClientPtr);
static int ProcSetPolyInstInfo(ClientPtr);
static int ProcSetPropLabel(ClientPtr);
static int ProcSetPropUID(ClientPtr);
static int ProcSetResLabel(ClientPtr);
static int ProcSetResUID(ClientPtr);
static int ProcGetClientAttributes(ClientPtr);
static int ProcGetClientLabel(ClientPtr);
static int ProcGetPropAttributes(ClientPtr);
static int ProcGetResAttributes(ClientPtr);
static int ProcMakeTPWindow(ClientPtr);
static int ProcMakeTrustedWindow(ClientPtr);
static int ProcMakeUntrustedWindow(ClientPtr);
static int SProcTsolDispatch(ClientPtr);
static int SProcSetPolyInstInfo(ClientPtr);
static int SProcSetPropLabel(ClientPtr);
static int SProcSetPropUID(ClientPtr);
static int SProcSetResLabel(ClientPtr);
static int SProcSetResUID(ClientPtr);
static int SProcGetClientAttributes(ClientPtr);
static int SProcGetClientLabel(ClientPtr);
static int SProcGetPropAttributes(ClientPtr);
static int SProcGetResAttributes(ClientPtr);
static int SProcMakeTPWindow(ClientPtr);
static int SProcMakeTrustedWindow(ClientPtr);
static int SProcMakeUntrustedWindow(ClientPtr);
static unsigned char TsolReqCode = 0;
static int tsolEventBase = -1;
static int ScreenStripeHeight[MAX_SCREENS] = {0, 0};
int tsolMultiLevel = TRUE;
static int OwnerUIDint;
static SecurityHook tsolSecHook;
char *name, unsigned int data_length,
/* XACE hook callbacks */
static CALLBACK(TsolCheckExtensionAccess);
static CALLBACK(TsolAceCheckPropertyAccess);
static CALLBACK(TsolCheckResourceIDAccess);
static CALLBACK(TsolProcessKeyboard);
/* other callbacks */
static CALLBACK(TsolClientStateCallback);
/*
* Initialize the extension. Main entry point for this loadable
* module.
*/
_X_EXPORT void
TsolExtensionInit(void)
{
int i;
/* sleep(20); */
/* This extension is supported on a labeled system */
if (!is_system_labeled()) {
return;
}
init_xtsol();
ErrorF("TsolExtensionInit: AddExtension failed for X Trusted Extensions\n");
return;
}
return;
/* Allocate storage in devPrivates */
ErrorF("TsolExtensionInit: Cannot allocate devPrivate.\n");
return;
}
/* Initialize security hooks */
pSecHook = &tsolSecHook;
NULL);
NULL);
/* Save original Proc vectors */
for (i = 0; i < PROCVECTORSIZE; i++) {
TsolSavedProcVector[i] = ProcVector[i];
}
/* Replace some of the original Proc vectors with our own TBD */
/* ProcVector[X_ChangeWindowAttributes] = ProcTsolChangeWindowAttributes; */
}
static CALLBACK(
{
int msgType;
int msgVerb;
int reqtype;
if (client->requestBuffer) {
} else {
reqtype = -1;
}
if (check_mode & (DIX_MODE)) { \
else \
check_mode &= ~(DIX_MODE); \
}
switch (rtype) {
case RT_GC:
break;
case RT_WINDOW: /* Drawables */
if (check_mode & DixCreateAccess) {
/* Replaces InitWindow hook */
check_mode &= ~(DixCreateAccess);
}
if (check_mode & DixReceiveAccess) {
TSOL_SPECIAL, rval, 0);
break;
}
if (check_mode & DixSetAttrAccess) {
TSOL_SPECIAL, rval, 0);
break;
}
/* The rest falls through to code shared with RT_PIXMAP */
case RT_PIXMAP:
/* Drawing operations use pixel access policy */
switch (reqtype) {
case X_PolyPoint:
case X_PolyLine:
case X_PolyArc:
case X_FillPoly:
case X_PolyFillRectangle:
case X_PolyFillArc:
case X_PutImage:
case X_PolyText8:
case X_PolyText16:
case X_ImageText8:
case X_ImageText16:
rval, 0);
rval, 0);
break;
/* Property protocols */
case X_ChangeProperty:
case X_DeleteProperty:
case X_GetProperty:
case X_ListProperties:
case X_RotateProperties:
rval, 0);
rval, 0);
break;
case X_ClearArea:
break;
}
break;
default:
break;
}
#ifndef NO_TSOL_DEBUG_MESSAGES
if (check_mode) { /* Any access mode bits not yet handled ? */
"policy not implemented for CheckResourceAccess, "
"rtype=0x%x (%s), mode=0x%x (%s)\n",
}
#endif /* !NO_TSOL_DEBUG_MESSAGES */
} else {
#ifdef NO_TSOL_DEBUG_MESSAGES
/* rest of the function is just printing error or debug messages */
return;
#else
/* Trace messages for debugging */
#endif /* NO_TSOL_DEBUG_MESSAGES */
}
"CheckResourceAccess(%s, %s, 0x%x, %s, %s) = %s\n",
}
static
{
switch (client->clientState) {
case ClientStateInitial:
/* Got a new connection */
break;
case ClientStateRunning:
break;
case ClientStateRetained: /* client disconnected */
break;
case ClientStateGone:
}
/* Audit disconnect */
}
break;
default:
break;
}
}
static void
{
}
/*
* Dispatch routine
*
*/
static int
{
int retval;
{
case X_SetPolyInstInfo:
break;
case X_SetPropLabel:
break;
case X_SetPropUID:
break;
case X_SetResLabel:
break;
case X_SetResUID:
break;
case X_GetClientAttributes:
break;
case X_GetClientLabel:
break;
case X_GetPropAttributes:
break;
case X_GetResAttributes:
break;
case X_MakeTPWindow:
break;
case X_MakeTrustedWindow:
break;
case X_MakeUntrustedWindow:
break;
default:
retval = BadRequest;
}
return (retval);
}
static int
{
int n;
int retval;
{
case X_SetPolyInstInfo:
break;
case X_SetPropLabel:
break;
case X_SetPropUID:
break;
case X_SetResLabel:
break;
case X_SetResUID:
break;
case X_GetClientAttributes:
break;
case X_GetClientLabel:
break;
case X_GetPropAttributes:
break;
case X_GetResAttributes:
break;
case X_MakeTPWindow:
break;
case X_MakeTrustedWindow:
break;
case X_MakeUntrustedWindow:
break;
default:
retval = BadRequest;
}
return (retval);
}
/*
* Individual routines
*/
static int
{
int n;
return (ProcSetPolyInstInfo(client));
}
static int
{
int n;
return (ProcSetPropLabel(client));
}
static int
{
int n;
return (ProcSetPropUID(client));
}
static int
{
int n;
return (ProcSetResLabel(client));
}
static int
{
int n;
return (ProcSetResUID(client));
}
static int
{
int n;
return (ProcGetClientAttributes(client));
}
static int
{
int n;
return (ProcGetClientLabel(client));
}
static int
{
int n;
return (ProcGetPropAttributes(client));
}
static int
{
int n;
return (ProcGetResAttributes(client));
}
static int
{
int n;
return (ProcMakeTPWindow(client));
}
static int
{
int n;
return (ProcMakeTrustedWindow(client));
}
static int
{
int n;
return (ProcMakeUntrustedWindow(client));
}
/*
* Set PolyInstantiation Info.
* Normally a get(prop) will
* get the prop. that has match sl, uid of the client. Setting
* enabled to true will get only the prop. corresponding to
* sl, uid specified instead of that of client. This is used
*/
static int
{
int err_code;
/*
* Check for policy here
*/
{
return (err_code);
}
return (client->noClientException);
}
static int
{
int err_code;
if (!pWin)
{
return (BadWindow);
}
{
return (err_code);
}
{
return (BadAtom);
}
/* first see if property already exists */
while (pProp)
{
break;
}
if (!pProp)
{
/* property does not exist */
return (BadAtom);
}
/* Initialize property created internally by server */
{
return(BadAlloc);
}
{
{
return (err_code);
}
}
return (client->noClientException);
}
static int
{
int err_code;
if (!pWin)
{
return (BadWindow);
}
{
return (err_code);
}
{
return (BadAtom);
}
/* first see if property already exists */
while (pProp)
{
break;
}
if (!pProp)
{
/* property does not exist */
return (BadAtom);
}
{
return (err_code);
}
/* Initialize property created internally by server */
{
*tsolpropP = AllocServerTsolProp();
return (BadAlloc);
}
return (client->noClientException);
}
static int
{
int err_code;
switch (stuff->resourceType)
{
case SESSIONHI: /* set server session HI */
{
return (err_code);
}
return (client->noClientException);
case SESSIONLO: /* set server session LO */
{
return (err_code);
}
return (client->noClientException);
case IsWindow:
if (pWin)
{
}
else
{
return (BadWindow);
}
{
return (err_code);
}
break;
case IsPixmap:
if (pMap)
{
}
else
{
return (BadPixmap);
}
{
return (err_code);
}
break;
default:
return (BadValue);
}
{
{
return (err_code);
}
}
/* generate the notify event for windows */
{
}
return (client->noClientException);
}
static int
{
int ScreenNumber;
int err_code;
switch (stuff->resourceType)
{
case STRIPEHEIGHT:
{
return (err_code);
}
/* set Screen Stripe Size */
return (client->noClientException);
case RES_OUID:
{
return (err_code);
}
return (client->noClientException);
case IsWindow:
if (pWin)
{
}
else
{
return (BadWindow);
}
{
return (err_code);
}
break;
case IsPixmap:
if (pMap)
{
}
else
{
return (BadPixmap);
}
{
return (err_code);
}
break;
default:
return (BadValue);
}
{
return (err_code);
}
return (client->noClientException);
}
static int
{
int n;
int err_code;
/* Valid window check */
{
return (BadWindow);
}
{
return (BadWindow);
}
{
return (err_code);
}
/* Transfer the client info to reply rec */
{
}
return (client->noClientException);
}
static int
{
int n;
int reply_length = 0;
int err_code;
Bool write_to_client = 0;
/* Valid window check */
{
return (BadWindow);
}
{
return (BadWindow);
}
{
return (err_code);
}
/* Transfer the client info to reply rec */
/* allocate temp storage for labels */
return (BadAlloc);
/* fill the fields as per request mask */
{
}
{
write_to_client = 1;
}
{
}
if (write_to_client == 1)
{
}
return (client->noClientException);
}
static int
{
int n;
int reply_length = 0;
int err_code;
Bool write_to_client = 0;
if (!pWin)
{
return (BadWindow);
}
{
return (err_code);
}
{
return (BadAtom);
}
/* first see if property already exists */
while (pProp)
{
break;
}
if (!pProp)
{
/* property does not exist */
return (BadAtom);
}
while (tmp_prop)
{
if (tsolpolyinstinfo.enabled)
{
{
break;
}
}
else
{
{
break;
}
}
}
if (!tsolprop)
{
return (client->noClientException);
}
{
}
/* allocate temp storage for labels */
return (BadAlloc);
/* fill the fields as per request mask */
{
}
{
write_to_client = 1;
}
{
}
if (write_to_client == 1)
{
}
return (client->noClientException);
}
static int
{
int n;
int reply_length = 0;
int err_code;
Bool write_to_client = 0;
{
}
{
}
{
if (pWin)
{
}
else
{
return (BadWindow);
}
{
return (err_code);
}
}
{
if (pMap)
{
}
else
{
return (BadPixmap);
}
{
return (err_code);
}
}
{
}
/* allocate temp storage for labels */
return (BadAlloc);
/* fill the fields as per request mask */
{
}
{
write_to_client = 1;
}
{
}
if (write_to_client == 1)
{
}
return (client->noClientException);
}
int
{
int err_code;
/*
* Session type single-level? This is set by the
* label builder
*/
return (client->noClientException);
}
#if defined(PANORAMIX)
if (!noPanoramiXExtension)
{
int j;
== NULL)
return BadWindow;
{
/* window should not be root but child of root */
{
return (BadWindow);
}
{
return (err_code);
}
{
}
}
} else
#endif
{
/* window should not be root but child of root */
{
return (BadWindow);
}
{
return (err_code);
}
{
}
}
/*
* Force kbd & ptr ungrab. This will cause
* a client
*/
return (client->noClientException);
}
/*
* Turn on window's Trusted bit
*/
static int
{
int err_code;
/* window should not be root but child of root */
{
return (BadWindow);
}
{
return (err_code);
}
/* Turn on Trusted bit of the window */
return (client->noClientException);
}
/*
* Turn off window's Trusted bit
*/
static int
{
int err_code;
/* window should not be root but child of root */
{
return (BadWindow);
}
{
return (err_code);
}
tsolinfo->forced_trust = 0;
return (client->noClientException);
}
/*
* Break keyboard & ptr grabs of clients other than
* the requesting client.
* Called from ProcMakeTPWindow.
*/
static void
{
if (kbdgrab) {
}
if (ptrgrab) {
}
}
/*
* Trusted Network interface module. Uses tsix API
*/
extern tsol_host_type_t tsol_getrhtype(char *);
static void
{
/* Get client attributes from the socket */
TSOL_LOG_PREFIX "Cannot get client attributes"
" for %s, getpeerucred failed: %s\n",
return;
}
/* Extract individual fields from the cred structure */
get the real process name out of /proc in the future
*/
/* Set privileges */
if (tsolMultiLevel) {
} else {
}
} else {
}
}
/*
* For remote hosts, the uid is determined during access control
* using Secure RPC
*/
} else {
}
/* Set Trusted Path for local clients */
}else {
}
else
tsolinfo->forced_trust = 0;
/* Set reasonable defaults for remote clients */
int errcode;
char hostbuf[NI_MAXHOST];
/* Use NI_NUMERICHOST to avoid DNS lookup */
if (errcode) {
} else {
}
}
}
/* setup audit context */
} else {
}
/* Audit id */
}
/* session id */
/* Audit mask */
} else {
} else {
}
}
ucred_free(uc);
}
static char *
{
char cred_area[MAX_AUTH_BYTES];
char verf_area[MAX_AUTH_BYTES];
char *temp_inmsg;
struct svc_req r;
memset((char *)&r, 0, sizeof(r));
goto bad1;
/* decode into msg */
goto bad2;
/* do the authentication */
goto bad2;
}
#ifdef SVR4
#else
#endif
goto bad2;
}
bad2:
Xfree(r.rq_clntcred);
bad1:
return ((char *)0); /* ((struct authdes_cred *) NULL); */
}
static Bool
{
}
extern int getdomainname(char *, int);
static XID
unsigned int data_length, char *data,
{
char domainname[128];
char netname[128];
char audit_ret;
int client_gidlen;
char *fullname;
/* Retrieve uid from SecureRPC */
ErrorF("Unable to authenticate Secure RPC client");
} else {
if (netname2user(fullname,
&client_uid, &client_gid,
&client_gidlen, &client_gidlist)) {
} else {
ErrorF("netname2user failed");
}
}
}
}
}
/*
* For multilevel desktop, limit connections to the trusted path
* i.e. global zone until a user logs in and the trusted stripe
* is in place. Unlabeled connections are rejected.
*/
if (HasTrustedPath(tsolinfo)) {
}
} else {
/*
* Workstation Owner set, client must be within label
* range or have trusted path
*/
(HasTrustedPath(tsolinfo))) {
}
} else {
/* Allow root from global zone */
} else {
/*
* Access check based on uid. Check if
* roles or other uids have been added by
* xhost +role@
*/
return ((XID)-1);
}
} else {
}
}
}
}
/* Audit the connection */
audit_val = 1;
} else {
audit_ret = 0; /* success */
audit_val = 0;
}
if (system_audit_on &&
int status;
u_short connect_port = 0;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
case AF_INET:
break;
case AF_INET6:
break;
}
} else {
}
if (!status)
}
return (auth_token);
}
static CALLBACK(
{
/* int count = rec->count; */
{
if (!hotkey.initialized)
InitHotKey(&hotkey);
HandleHotKey();
}
}
_X_HIDDEN int
{
int returnVal = XTSOL_ALLOW;
int reqtype;
if (client->requestBuffer) {
} else {
reqtype = -1;
}
if (check_mode & (DIX_MODE)) { \
if (!isPolyProp && \
returnVal = XTSOL_IGNORE; \
check_mode &= ~(DIX_MODE); \
}
/* Don't need to check for write access on property creation */
if (check_mode & DixCreateAccess) {
}
if (check_mode) { /* Any access mode bits not yet handled ? */
#ifndef NO_TSOL_DEBUG_MESSAGES
"policy not implemented for CheckPropertyAccess, "
"mode=0x%x (%s)\n", check_mode,
#endif /* !NO_TSOL_DEBUG_MESSAGES */
}
}
#ifndef NO_TSOL_DEBUG_MESSAGES
"CheckPropertyAccess(%s, 0x%x, %s, %s) = %s\n",
#endif /* !NO_TSOL_DEBUG_MESSAGES */
/* Only returns allow if all checks succeeded */
return returnVal;
}
static CALLBACK(
{
}
}
static CALLBACK(
{
}
}
#ifdef UNUSED
/*
* Return TRUE if host is cipso
*/
int
host_is_cipso(int fd)
{
char *rhost;
extern tsol_host_type_t tsol_getrhtype(char *);
perror("getsockname: failed\n");
return FALSE;
}
return TRUE;
}
return FALSE;
}
#endif