XORG_NV/sun-src/xc/programs/Xserver/tsol/tsolextension.c
changeset 36 07b00e5ea8c8
parent 0 b949c5054bc4
child 64 c03273ff2fb9
--- a/XORG_NV/sun-src/xc/programs/Xserver/tsol/tsolextension.c	Fri Jun 23 19:18:21 2006 -0700
+++ b/XORG_NV/sun-src/xc/programs/Xserver/tsol/tsolextension.c	Mon Jun 19 15:45:03 2006 -0700
@@ -26,7 +26,7 @@
  * of the copyright holder.
  */ 
 
-#pragma ident   "@(#)tsolextension.c 1.11     06/03/07 SMI"
+#pragma ident   "@(#)tsolextension.c 1.16     06/06/08 SMI"
 
 #include <stdio.h>
 #include <bsm/auditwrite.h>
@@ -38,6 +38,7 @@
 #include <sys/wait.h>
 #include <ucred.h>
 #include <netinet/in.h>
+#include <netdb.h>
 #include <arpa/inet.h>
 #include <sys/tsol/tndb.h>
 #include <strings.h>
@@ -69,7 +70,8 @@
 #define  MAX_SCREENS        3         /* screens allowed */
 #define EXTNSIZE 128
 
-extern Bool il_enabled;
+#define SECURE_RPC_AUTH	"SUN-DES-1"
+#define SECURE_RPC_LEN	9
 
 extern bslabel_t *lookupSL();
 extern void (*ReplySwapVector[]) ();
@@ -108,6 +110,8 @@
 static void BreakAllGrabs(ClientPtr client);
 
 extern void init_xtsol();
+extern void init_win_privsets();
+extern void free_win_privsets();
 extern int DoScreenStripeHeight(int screen_num);
 extern int AddUID(int *userid);
 
@@ -121,6 +125,7 @@
 extern int tsolPixmapPrivateIndex;
 
 static HotKeyRec hotkey = {FALSE, 0, 0, 0, 0};
+static int tsolMultiLevel = TRUE;
 
 int OwnerUIDint;
 extern uid_t OwnerUID;
@@ -202,6 +207,10 @@
 extern int ProcTsolGetImage(ClientPtr client);
 extern int ProcTsolQueryTree(ClientPtr client);
 extern int ProcTsolQueryPointer(ClientPtr client);
+extern int ProcTsolQueryExtension(ClientPtr client);
+extern int ProcTsolListExtensions(ClientPtr client);
+extern int ProcTsolMapWindow(ClientPtr client);
+extern int ProcTsolMapSubwindows(ClientPtr client);
 
 /*
  * Initialize the extension. Main entry point for this loadable
@@ -225,9 +234,11 @@
 		return;
 	}
 
+	tsolMultiLevel = TRUE;
 	(void) setpflags(PRIV_AWARE, 1);
 
 	init_xtsol();
+	init_win_privsets();
 
 	extEntry = AddExtension(TSOLNAME, TSOL_NUM_EVENTS, TSOL_NUM_ERRORS,
 		ProcTsolDispatch, SProcTsolDispatch, TsolReset, 
@@ -238,6 +249,7 @@
 		return;
 	}
 
+	extEntry->secure = TRUE;
         TsolReqCode = (unsigned char) extEntry->base;
         tsolEventBase = extEntry->eventBase;
 
@@ -333,6 +345,10 @@
 	ProcVector[X_GetImage] = ProcTsolGetImage;
 	ProcVector[X_QueryTree] = ProcTsolQueryTree;
 	ProcVector[X_QueryPointer] = ProcTsolQueryPointer;
+	ProcVector[X_QueryExtension] = ProcTsolQueryExtension;
+	ProcVector[X_ListExtensions] = ProcTsolListExtensions;
+	ProcVector[X_MapWindow] = ProcTsolMapWindow;
+	ProcVector[X_MapSubwindows] = ProcTsolMapSubwindows;
 
 }
 
@@ -388,7 +404,6 @@
 		case X_PolyFillRectangle:
 		case X_PolyFillArc:
 		case X_PutImage:
-		case X_GetImage:
 		case X_PolyText8:
 		case X_PolyText16:
 		case X_ImageText8:
@@ -475,19 +490,33 @@
 		if (tsolinfo != NULL && tsolinfo->privs != NULL) {
 			priv_freeset(tsolinfo->privs);
 		}
+		/* Audit disconnect */
+		if (system_audit_on && (au_preselect(AUE_ClientDisconnect, &(tsolinfo->amask),
+                              AU_PRS_BOTH, AU_PRS_USECACHE) == 1)) {
+			auditwrite(AW_PRESELECT, &(tsolinfo->amask),AW_END);
+			auditwrite(AW_EVENTNUM, AUE_ClientDisconnect,
+                               AW_XCLIENT, client->index,
+			       AW_SLABEL, tsolinfo->sl,
+                               AW_RETURN, 0, 0, AW_WRITE, AW_END);
+
+			tsolinfo->flags &= ~TSOL_DOXAUDIT;
+			tsolinfo->flags &= ~TSOL_AUDITEVENT;
+			auditwrite(AW_FLUSH, AW_END);
+			auditwrite(AW_DISCARDRD, tsolinfo->asaverd, AW_END);
+			auditwrite(AW_NOPRESELECT, AW_END);
+		}
 		break;
+
 	default:
                 break;
 	}
 
 }
 
-/*
- * Reset routine. Don't know what to put here yet
- */
 static void
 TsolReset()
 {
+	free_win_privsets();
 }
 
 /*
@@ -1145,7 +1174,7 @@
     rep.pid = (CARD32) res_tsolinfo->pid;
     rep.gid = (CARD32) res_tsolinfo->gid;
     rep.auditid = (CARD32) res_tsolinfo->auid;
-    rep.sessionid = (CARD32) res_tsolinfo->sid;
+    rep.sessionid = (CARD32) res_tsolinfo->asid;
     rep.iaddr = (CARD32) res_tsolinfo->iaddr;
     rep.length = (CARD32) 0;
 
@@ -1499,12 +1528,24 @@
 {
     WindowPtr pWin, pParent;
     int       err_code;
+    TsolInfoPtr  tsolinfo;
     extern void ReflectStackChange(WindowPtr, WindowPtr, VTKind);
 
 
     REQUEST(xMakeTPWindowReq);
     REQUEST_SIZE_MATCH(xMakeTPWindowReq);
 
+    /*
+     * Session type single-level? This is set by the 
+     * label builder
+     */
+    tsolinfo = GetClientTsolInfo(client);
+    if (tsolinfo && HasTrustedPath(tsolinfo) && 
+		blequal(&SessionLO, &SessionHI) && stuff->id == 0) {
+	tsolMultiLevel = FALSE;
+	return (client->noClientException);
+    }
+
     pWin = LookupWindow(stuff->id, client);
 
     /* window should not be root but child of root */
@@ -1640,6 +1681,11 @@
 	priv_set_t *privs;
 	const au_tid64_addr_t *tid64;
 	const au_mask_t *amask;
+	au_mask_t mask;		/* user audit mask */
+	socklen_t namelen;
+	struct passwd *pw;
+	struct auditinfo auinfo;
+	struct auditinfo *pauinfo;
 	OsCommPtr oc = (OsCommPtr)client->osPrivate;
 	register ConnectionInputPtr oci = oc->input;
 	int fd = oc->fd;
@@ -1647,7 +1693,6 @@
 	extern  au_id_t ucred_getauid(const ucred_t *uc);
 	extern  au_asid_t ucred_getasid(const ucred_t *uc);
 	extern  const au_mask_t *ucred_getamask(const ucred_t *uc);
-	extern  const au_tid64_addr_t *ucred_getatid(const ucred_t *uc);
 
 	TsolInfoPtr tsolinfo = (TsolInfoPtr)
 		(client->devPrivates[tsolClientPrivateIndex].ptr);
@@ -1672,34 +1717,19 @@
 	tsolinfo->sl = (bslabel_t *)lookupSL(sl);
 
 	/* Set privileges */
-        privs = (priv_set_t *)ucred_getprivset(uc, PRIV_EFFECTIVE);
 	if ((tsolinfo->privs = priv_allocset()) != NULL) {
-		if (privs == NULL) {
-			priv_emptyset(tsolinfo->privs);
+		if (tsolMultiLevel) {
+			privs = (priv_set_t *)ucred_getprivset(uc, PRIV_EFFECTIVE);
+			if (privs == NULL) {
+				priv_emptyset(tsolinfo->privs);
+			} else {
+				priv_copyset(privs, tsolinfo->privs);
+			}
 		} else {
-			priv_copyset(privs, tsolinfo->privs);
+			priv_fillset(tsolinfo->privs); 
 		}
 	}
 
-	/* Set audit info */
-	tsolinfo->auinfo.ai_auid = ucred_getauid(uc);
-	tsolinfo->auinfo.ai_asid = ucred_getasid(uc);
-	if ((amask = ucred_getamask(uc)) != NULL) {
-	    tsolinfo->auinfo.ai_mask = *amask;
-	}
-	if ((tid64 = ucred_getatid(uc)) != NULL) {
-#ifdef	_LP64
-	    tsolinfo->auinfo.ai_termid = *tid64;
-#else
-	    tsolinfo->auinfo.ai_termid.at_type = tid64->at_type;
-	    tsolinfo->auinfo.ai_termid.at_port = (tid64->at_port.at_major & MAXMIN32);
-	    tsolinfo->auinfo.ai_termid.at_port |= (tid64->at_port.at_major & MAXMAJ32) <<
-                NBITSMINOR32;
-	    tsolinfo->auinfo.ai_termid.at_addr[0] = *(tid64->at_addr);
-#endif
-	}
-	ucred_free(uc);
-
 	tsolinfo->priv_debug = FALSE;
 
 
@@ -1717,59 +1747,148 @@
 	/* Set Trusted Path for local clients */
 	if (tsolinfo->zid == GLOBAL_ZONEID) {
 		tsolinfo->trusted_path = TRUE;
-		client->trustLevel = XSecurityClientTrusted;
 	}else {
 		tsolinfo->trusted_path = FALSE;
+	}
+
+	if (tsolinfo->trusted_path || !tsolMultiLevel)
+		client->trustLevel = XSecurityClientTrusted;
+	else
 		client->trustLevel = XSecurityClientUntrusted;
-	}
 
         tsolinfo->forced_trust = 0;
         tsolinfo->iaddr = 0;
 
 	bsllow(&admin_low);
+
+	namelen = sizeof (tsolinfo->saddr);
+	if (getpeername(fd, (struct sockaddr *)&tsolinfo->saddr, &namelen) != 0) {
+		return;
+	}
+
 	/* Set reasonable defaults for remote clients */
 	if (tsolinfo->client_type == CLIENT_REMOTE) {
+		int errcode;
+		char hostbuf[NI_MAXHOST];
+		tsol_host_type_t host_type; 
 		struct sockaddr sname;
-		socklen_t namelen;
-		char *rhost;
-		tsol_host_type_t host_type; 
-		struct sockaddr_in *so = (struct sockaddr_in *)&sname;
 		extern tsol_host_type_t tsol_getrhtype(char *);
 
-		namelen = sizeof (sname);
-		if (getpeername(fd, &sname, &namelen) == 0) {
-			tsolinfo->iaddr = so->sin_addr.s_addr;
-			rhost = inet_ntoa(so->sin_addr);
-			host_type = tsol_getrhtype(rhost);
+		/* Use NI_NUMERICHOST to avoid DNS lookup */
+		errcode = getnameinfo((struct sockaddr *)&(tsolinfo->saddr), namelen,
+			hostbuf, sizeof(hostbuf), NULL, 0, NI_NUMERICHOST);
+
+		if (errcode) {
+			perror(gai_strerror(errcode));
+		} else {
+			host_type = tsol_getrhtype(hostbuf);
 			if ((host_type == SUN_CIPSO) && 
-					blequal(tsolinfo->sl, &admin_low)) {
+				blequal(tsolinfo->sl, &admin_low)) {
 				tsolinfo->trusted_path = TRUE;
 				client->trustLevel = XSecurityClientTrusted;
 				priv_fillset(tsolinfo->privs);
 			}
 		}
 	}
-	/* TBD: Initialize audit context here */
-	{
-		au_mask_t mask;
-		struct passwd *pw = getpwuid(getuid());
-		if ((pw != NULL) && (!au_user_mask(pw->pw_name, &mask))) {
-	if (!getaudit(&tsolinfo->aw_auinfo)) {
-			tsolinfo->aw_auinfo.ai_mask.am_success = mask.am_success;
-			tsolinfo->aw_auinfo.ai_mask.am_failure = mask.am_failure;
-                    }
-	 }
-		tsolinfo->sid = 0;
+
+	/* setup audit context */
+	if (getaudit(&auinfo) == 0) {
+	    pauinfo = &auinfo;
+	} else {
+	    pauinfo = NULL;
+	}
+
+	/* Audit id */
+	tsolinfo->auid = ucred_getauid(uc);
+	if (tsolinfo->auid == AU_NOAUDITID) {
+	    tsolinfo->auid = UID_NOBODY;
 	}
+
+	/* session id */
+	tsolinfo->asid = ucred_getasid(uc);
+
+	/* Audit mask */
+	if ((amask = ucred_getamask(uc)) != NULL) {
+	    tsolinfo->amask = *amask;
+	} else {
+	    if (pauinfo != NULL) {
+	        tsolinfo->amask = pauinfo->ai_mask;
+	    } else {
+	        tsolinfo->amask.am_failure = 0; /* clear the masks */
+	        tsolinfo->amask.am_success = 0;
+	    }
+	}
+
+	tsolinfo->asaverd = 0;
+
+	ucred_free(uc);
 }
 
+static enum auth_stat tsol_why;
+
+static char * 
+tsol_authdes_decode(inmsg, len)
+char *inmsg;
+int  len;
+{
+    struct rpc_msg  msg;
+    char            cred_area[MAX_AUTH_BYTES];
+    char            verf_area[MAX_AUTH_BYTES];
+    char            *temp_inmsg;
+    struct svc_req  r;
+    bool_t          res0, res1, auth_ret;
+    XDR             xdr;
+    SVCXPRT         xprt;
+    extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
+
+    temp_inmsg = (char *) xalloc(len);
+    memmove(temp_inmsg, inmsg, len);
+
+    memset((char *)&msg, 0, sizeof(msg));
+    memset((char *)&r, 0, sizeof(r));
+    memset(cred_area, 0, sizeof(cred_area));
+    memset(verf_area, 0, sizeof(verf_area));
+
+    msg.rm_call.cb_cred.oa_base = cred_area;
+    msg.rm_call.cb_verf.oa_base = verf_area;
+    tsol_why = AUTH_FAILED; 
+    xdrmem_create(&xdr, temp_inmsg, len, XDR_DECODE);
+
+    if ((r.rq_clntcred = (caddr_t) xalloc(MAX_AUTH_BYTES)) == NULL)
+        goto bad1;
+    r.rq_xprt = &xprt;
+
+    /* decode into msg */
+    res0 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_cred)); 
+    res1 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_verf));
+    if ( ! (res0 && res1) )
+         goto bad2;
+
+    /* do the authentication */
+
+    r.rq_cred = msg.rm_call.cb_cred;        /* read by opaque stuff */
+    if (r.rq_cred.oa_flavor != AUTH_DES) {
+        tsol_why = AUTH_TOOWEAK;
+        goto bad2;
+    }
+#ifdef SVR4
+    if ((tsol_why = __authenticate(&r, &msg)) != AUTH_OK) {
+#else
+    if ((tsol_why = _authenticate(&r, &msg)) != AUTH_OK) {
+#endif
+            goto bad2;
+    }
+    return (((struct authdes_cred *) r.rq_clntcred)->adc_fullname.name); 
+
+bad2:
+    Xfree(r.rq_clntcred);
+bad1:
+    return ((char *)0); /* ((struct authdes_cred *) NULL); */
+}
 static Bool
-CheckNetName (addr, len, closure)
-    unsigned char    *addr;
-    short            len;
-    pointer         closure;
+TsolCheckNetName (unsigned char *addr, short len, pointer closure)
 {
-    return (len == strlen ((char *) closure) &&
+    return (len == (short) strlen ((char *) closure) &&
             strncmp ((char *) addr, (char *) closure, len) == 0);
 }
 
@@ -1778,40 +1897,58 @@
 TsolCheckAuthorization(unsigned int name_length, char *name, unsigned int data_length, 
 	char *data, ClientPtr client, char **reason)
 {
-	TsolInfoPtr tsolinfo = GetClientTsolInfo(client);
 	char	domainname[128];
 	char	netname[128];
+	char	audit_ret;
+	u_int	audit_val;
+	uid_t	client_uid;
+	gid_t	client_gid;
+	int	client_gidlen;
+	char	*fullname;
+	gid_t	client_gidlist;
+	XID	auth_token = (XID)(-1);
+	TsolInfoPtr tsolinfo = GetClientTsolInfo(client);
+	extern	int getdomainname(char *, int);
 
+	if (tsolinfo->uid == -1) {
+		/* Retrieve uid from SecureRPC */
+		if (strncmp(name, SECURE_RPC_AUTH, (size_t)name_length) == 0) {
+			fullname = tsol_authdes_decode(data, data_length);
+			if (fullname == NULL) {
+				ErrorF("Unable to authenticate Secure RPC client");
+			} else {
+				if (netname2user(fullname, 
+					&client_uid, &client_gid, 
+					&client_gidlen, &client_gidlist)) {
+					tsolinfo->uid = client_uid;
+				} else {
+					ErrorF("netname2user failed");
+				}
+			}
+		}
+	}
 	 
+	if (tsolinfo->uid == (uid_t)-1) {
+		tsolinfo->uid = UID_NOBODY; /* uid not available */
+	}
+
 	/* Workstation Owner not set */
 	if (OwnerUID == (uid_t )(-1)) {
 		if (HasTrustedPath(tsolinfo)) {
-			return (CheckAuthorization(name_length, name, data_length,
-				data, client, reason));
+			auth_token = CheckAuthorization(name_length, name, data_length,
+				data, client, reason);
 		}
 	} else {
-		/* Reject all invalid SLs or invalid uids for local hosts */
-		if (tsolinfo->sl == NULL || !bslvalid(tsolinfo->sl) || 
-			(tsolinfo->client_type == CLIENT_LOCAL && 
-				tsolinfo->uid == (uid_t)-1)) {
-			return ((XID)-1);
-		}
-
-		/* uid needs to be retrieved from Secure RPC */
-		if (tsolinfo->uid == -1) {
-			/* Temporary kludge */
-			tsolinfo->uid = OwnerUID;
-		}
-
 		/* 
 		 * Workstation Owner set, client must be within label
 		 * range or have trusted path
 		 */
 		if (tsolinfo->uid == OwnerUID) {
-			if ((bldominates(tsolinfo->sl, &SessionLO) &&
-				bldominates(&SessionHI, tsolinfo->sl)) ||
-				(HasTrustedPath(tsolinfo))) {
-				return ((XID)(tsolinfo->uid));
+			if (tsolinfo->sl != NULL && 
+					(bldominates(tsolinfo->sl, &SessionLO) &&
+					bldominates(&SessionHI, tsolinfo->sl)) || 
+					(HasTrustedPath(tsolinfo))) {
+				auth_token = (XID)(tsolinfo->uid);
 			}
 		} else {
 			if (tsolinfo->uid != 0) {
@@ -1820,7 +1957,7 @@
 				if (!user2netname(netname, tsolinfo->uid, domainname)) {
 					return ((XID)-1);
 				}
-				if (ForEachHostInFamily (FamilyNetname, CheckNetName,
+				if (ForEachHostInFamily (FamilyNetname, TsolCheckNetName,
 						(pointer) netname)) {
 					return ((XID)(tsolinfo->uid));
 				} else {
@@ -1830,10 +1967,63 @@
 			} else
 				/* Allow all connections from global zones for now */
 				if (HasTrustedPath(tsolinfo)) {
-					return ((XID)(tsolinfo->uid));
+					auth_token = (XID)(tsolinfo->uid);
 			}
 		}
 	}
+
+	/* Audit the connection */
+	if (auth_token == (XID)(-1)) {
+		audit_ret = (char )-1; /* failure */
+		audit_val = 1;
+	} else {
+		audit_ret = 0; /* success */
+		audit_val = 0;
+	}
+
+	if (system_audit_on &&
+		(au_preselect(AUE_ClientConnect, &(tsolinfo->amask),
+                      AU_PRS_BOTH, AU_PRS_USECACHE) == 1)) {
+		int status;
+		u_short connect_port = 0;
+		struct in_addr *connect_addr = NULL;
+		struct sockaddr_in *sin;
+		struct sockaddr_in6 *sin6;
+
+		switch (tsolinfo->saddr.ss_family) {
+                        case AF_INET:
+                                sin = (struct sockaddr_in *)&(tsolinfo->saddr);
+                                connect_addr = &(sin->sin_addr);
+                                connect_port = sin->sin_port;
+                                break;
+                        case AF_INET6:
+                                sin6 = (struct sockaddr_in6 *)&(tsolinfo->saddr);
+                                connect_addr = (struct in_addr *)&(sin6->sin6_addr);
+                                connect_port = sin6->sin6_port;
+                                break;
+		}
+
+		if (connect_addr == NULL || connect_port == 0) {
+        		status = auditwrite(AW_EVENTNUM, AUE_ClientConnect,
+				AW_XCLIENT, client->index,
+				AW_SLABEL, tsolinfo->sl,
+				AW_RETURN, audit_ret, audit_val,
+				AW_WRITE, AW_END);
+		} else {
+        		status = auditwrite(AW_EVENTNUM, AUE_ClientConnect,
+				AW_XCLIENT, client->index,
+				AW_SLABEL, tsolinfo->sl,
+				AW_INADDR, connect_addr,
+				AW_IPORT, connect_port,
+				AW_RETURN, audit_ret, audit_val,
+				AW_WRITE, AW_END);
+		}
+
+		if (!status)
+			(void) auditwrite(AW_FLUSH, AW_END);
+		tsolinfo->flags &= ~TSOL_DOXAUDIT;
+		tsolinfo->flags &= ~TSOL_AUDITEVENT;
+	}
 }
 
 static void