[prev in list] [next in list] [prev in thread] [next in thread] 

List:       freedesktop-xorg
Subject:    [Xorg] Draft proposal for getpeer* based X authentication
From:       Alan Coopersmith <Alan.Coopersmith () Sun ! COM>
Date:       2004-04-27 6:46:55
Message-ID: 408E01DF.3090609 () sun ! com
[Download RAW message or body]

I had hoped to send this out earlier so more people would have a chance
to read it before the conference this week, but got busy.  In a nutshell,
this uses the new "server-interpreted" extensible scheme to xhost authentication
to allow for uid/gid-based authentication on platforms that can get the
credentials of the user on the other end of a local transport (i.e. OpenBSD
with getpeereid, Solaris 10 with getpeerucred, etc.)

I've got an implementation that seems to work well on Solaris with a patch
to a single server-side source file (see the attachment), but I haven't had
a chance to try it out on anything else yet.

Open questions:
  - Is this the right definition?  Do we need to specify some sort of
    @<authenticationdomain> optional qualifier?
  - What process do we want to follow for this?  One of the goals of the
    SI authentication method was to allow a much lighter weight process
    (both technically and procedurally) for adding new authentication schemes,
    but we haven't defined yet what the procedure is we want to use for additions
    like this.  (The process shouldn't be too heavy since the risk of damage is
    low if we get it wrong - the namespace is huge for registering new schemes,
    and most new schemes won't be formally adopted as part of the official standards,
    nor is a platform required to implement any of them to be considered standards
    compliant.)

-----------
Proposed Server-interpreted Authentication Types "localuser" and "localgroup":

On systems which can determine in a secure fashion the credentials of a client
process, the "localuser" and "localgroup" authentication methods provide access
based on those credentials.  The format of the values provided is platform
specific.  For POSIX & UNIX platforms, if the value starts with the character
'#', the rest of the string shall be treated as a decimal uid or gid, otherwise
the string is defined as a user name or group name.

Systems offering this MUST not simply trust a user supplied value (such as an
environment variable or IDENT protocol response).  It is expected many systems
will only support this for clients running on the same host using a local IPC
transport.

Examples:
         xhost +SI:localuser:alanc
         xhost +SI:localuser:#1234
         xhost +SI:localgroup:wheel
         xhost +SI:localgroup:#0
-----------

Maybe we'll get a chance to discuss this in Boston this week - see you there!
(Except for those on these lists who are not going, of course. 8-)

-- 
	-Alan Coopersmith-           alan.coopersmith@sun.com
	 Sun Microsystems, Inc. - X Window System Engineering

["access.c-patch.txt" (text/plain)]

--- head/cvs-rw/xc/programs/Xserver/os/access.c	Fri Apr 23 12:54:28 2004
+++ head/sx86/xc/programs/Xserver/os/access.c	Sat Apr 24 19:50:12 2004
@@ -227,6 +227,9 @@
 		    int /*len*/,
 		    int /* addingLocalHosts */);
 
+int LocalClientCredAndGroups(ClientPtr client, int *pUid, int *pGid, 
+  int **pSuppGids, int *nSuppGids);
+
 /* XFree86 bug #156: To keep track of which hosts were explicitly requested in
    /etc/X<display>.hosts, we've added a requested field to the HOST struct,
    and a LocalHostRequested variable.  These default to FALSE, but are set
@@ -1361,7 +1364,7 @@
 
 /*
  * Return the uid and gid of a connected local client
- * or the uid/gid for nobody those ids cannot be determinded
+ * or the uid/gid for nobody those ids cannot be determined
  * 
  * Used by XShm to test access rights to shared memory segments
  */
@@ -1368,6 +1371,23 @@
 int
 LocalClientCred(ClientPtr client, int *pUid, int *pGid)
 {
+    return LocalClientCredAndGroups(client, pUid, pGid, NULL, NULL);
+}
+
+/*
+ * Return the uid and all gids of a connected local client
+ * or the uid/gid for nobody those ids cannot be determined
+ * 
+ * If the caller passes non-NULL values for pSuppGids & nSuppGids,
+ * they are responsible for calling XFree(*pSuppGids) to release the
+ * memory allocated for the supplemental group ids list.
+ *
+ * Used by localuser & localgroup ServerInterpreted access control forms below
+ */
+int
+LocalClientCredAndGroups(ClientPtr client, int *pUid, int *pGid, 
+			 int **pSuppGids, int *nSuppGids)
+{
 #if defined(HAS_GETPEEREID) || defined(HAS_GETPEERUCRED) || defined(SO_PEERCRED)
     int fd;
     XtransConnInfo ci;
@@ -1381,6 +1401,11 @@
     socklen_t so_len = sizeof(peercred);
 #endif
 
+    if (pSuppGids != NULL)
+	*pSuppGids = NULL;
+    if (nSuppGids != NULL)
+	*nSuppGids = 0;
+
     if (client == NULL)
 	return -1;
     ci = ((OsCommPtr)client->osPrivate)->trans_conn;
@@ -1409,6 +1434,21 @@
 	*pUid = ucred_geteuid(peercred);
     if (pGid != NULL)
 	*pGid = ucred_getegid(peercred);
+    if (pSuppGids != NULL && nSuppGids != NULL) {
+	const gid_t *gids;
+	*nSuppGids = ucred_getgroups(peercred, &gids);
+	if (*nSuppGids > 0) {
+	    *pSuppGids = xalloc(sizeof(int) * (*nSuppGids));
+	    if (*pSuppGids == NULL) {
+		*nSuppGids = 0;
+	    } else {
+		int i;
+		for (i = 0 ; i < *nSuppGids; i++) {
+		    (*pSuppGids)[i] = (int) gids[i];
+		}
+	    }
+	}
+    }
     ucred_free(peercred);
     return 0;
 #elif defined(SO_PEERCRED)
@@ -1422,6 +1462,7 @@
 #endif
 #else
     /* No system call available to get the credentials of the peer */
+#define NO_LOCAL_CLIENT_CRED
     return -1;
 #endif
 }
@@ -2190,6 +2231,123 @@
 }
 #endif /* IPv6 */
 
+#if !defined(NO_LOCAL_CLIENT_CRED)
+/***
+ * "localuser" & "localgroup" server interpreted types
+ *
+ * Allows local connections from a given local user or group
+ */
+
+#include <pwd.h>
+#include <grp.h>
+
+#define LOCAL_USER 1
+#define LOCAL_GROUP 2
+
+typedef struct {
+    int credType;
+} siLocalCredPrivRec, *siLocalCredPrivPtr;
+
+static siLocalCredPrivRec siLocalUserPriv = { LOCAL_USER };
+static siLocalCredPrivRec siLocalGroupPriv = { LOCAL_GROUP };
+
+/* Maximum length of a user/group name/id string, including trailing NUL */
+#define SI_LOCALCRED_MAXLEN 33
+
+static Bool
+siLocalCredGetId(const char *addr, int len, siLocalCredPrivPtr lcPriv, int *id)
+{
+    char addrbuf[SI_LOCALCRED_MAXLEN];
+
+    if (len >= SI_LOCALCRED_MAXLEN) {
+	return FALSE;
+    }
+
+    memcpy(addrbuf, addr, len);
+    addrbuf[len] = '\0';
+
+    if (addr[0] == '#') { /* numeric id */
+	char *cp;
+	errno = 0;
+	*id = strtol(addrbuf + 1, &cp, 0);
+	if ((errno != 0) || (cp == (addrbuf+1))) {
+	    return FALSE;
+	}
+    } else { /* non-numeric name */
+	if (lcPriv->credType == LOCAL_USER) {
+	    struct passwd *pw = getpwnam(addrbuf);
+
+	    if (pw == NULL) {
+		return FALSE;
+	    } else {
+		*id = (int) pw->pw_uid;
+	    }
+	} else { /* group */
+	    struct group *gr = getgrnam(addrbuf);
+
+	    if (gr == NULL) {
+		return FALSE;
+	    } else {
+		*id = (int) gr->gr_gid;
+	    }
+	}
+    }
+    return TRUE;
+}
+
+static Bool 
+siLocalCredAddrMatch(int family, pointer addr, int len,
+  const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv)
+{
+    int connUid, connGid, *connSuppGids, connNumSuppGids, siAddrId;
+    siLocalCredPrivPtr lcPriv = (siLocalCredPrivPtr) typePriv;
+
+    if (LocalClientCredAndGroups(client, &connUid, &connGid,
+      &connSuppGids, &connNumSuppGids) == -1) {
+	return FALSE;
+    }
+
+    if (siLocalCredGetId(siAddr, siAddrlen, lcPriv, &siAddrId) == FALSE) {
+	return FALSE;
+    }
+
+    if (lcPriv->credType == LOCAL_USER) {
+	if (connUid == siAddrId) {
+	    return TRUE;
+	}
+    } else {
+	if (connGid == siAddrId) {
+	    return TRUE;
+	}
+	if (connSuppGids != NULL) {
+	    int i;
+
+	    for (i = 0 ; i < connNumSuppGids; i++) {
+		if (connSuppGids[i] == siAddrId) {
+		    xfree(connSuppGids);
+		    return TRUE;
+		}
+	    }
+	    xfree(connSuppGids);
+	}
+    }
+    return FALSE;
+}
+
+static int
+siLocalCredCheckAddr(const char *addrString, int length, void *typePriv)
+{
+    int len = length;
+    int id;
+
+    if (siLocalCredGetId(addrString, length, 
+	(siLocalCredPrivPtr)typePriv, &id) == FALSE) {
+	len = -1;
+    }
+    return len;
+}
+#endif /* localuser */
+
 static void
 siTypesInitialize(void)
 {
@@ -2197,4 +2355,10 @@
 #if defined(IPv6) && defined(AF_INET6)
     siTypeAdd("ipv6", siIPv6AddrMatch, siIPv6CheckAddr, NULL);
 #endif
+#if !defined(NO_LOCAL_CLIENT_CRED)
+    siTypeAdd("localuser", siLocalCredAddrMatch, siLocalCredCheckAddr, 
+      &siLocalUserPriv);
+    siTypeAdd("localgroup", siLocalCredAddrMatch, siLocalCredCheckAddr, 
+      &siLocalGroupPriv);
+#endif
 }


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic