Re: [gamin] socket credentials patch for NetBSD



Daniel Veillard wrote:

  The fact it won't change the protocol sounds good. I don't understand your
unique ID idea, it won't solve the lack of authentification.

Please correct me if I'm wrong, but it looked like the extent of the authentication that gamin does is that the server and the client mutually check that the process at the other end of the socket shares the same UID as itself. Since we can easily get this information on all of Linux, FreeBSD, NetBSD, OpenBSD, and BSD/OS, it's easy to make gamin work on all of those platforms with the same "strength of authentication".

The authentication routines in gam_channel.c also collect and save the PID of the process at the other end of the socket, but that information is used only in debugging messages to help distinguish between different clients. My point is that since the PID is used only for that purpose, gamin doesn't actually care if instead of saving the PID, we saved something else instead. In fact, we could just be saving a "-1" every time, and gamin would still work properly, but in the interests of better debugging messages, we should still try to save a unique integer for each connecting client.

Is my understanding correct?

If not, I'd like to change the name of the "pid" and "pidname" fields in various structs to be "id" and "idname", and change the routines that {get,set}_{pid,pidname} to be {get,set}_{id,idname}. This would reflect the fact that those aren't necessarily PIDs and pid-to-name strings, though I would keep it that way on Linux and FreeBSD where that information is easily discovered.

Would that be okay?


  I don't understand the rationale. Why do you try to mix semantic changes
with what should be a patch to Just Make It Work on your platform. I would
really prefer a patch which ensure functional behaviour on FreeBSD from you,
then we can discuss if framework changes are really needed. I'm not opposed
to change the function names, I dislike that being mixed with what should be primarily a portability patch.

I've attached a patch that just saves a "-1" instead of the PID in the connection information. NetBSD and FreeBSD still pass all of the regression test scenarios with this patch.

I'll submit another patch for the other changes I described pending the outcome of this thread.

	Cheers,

	-- Johnny Lam <jlam NetBSD org>
Index: libgamin/gam_api.c
===================================================================
RCS file: /cvs/gnome/gamin/libgamin/gam_api.c,v
retrieving revision 1.39
diff -u -r1.39 gam_api.c
--- libgamin/gam_api.c	5 Aug 2005 14:06:49 -0000	1.39
+++ libgamin/gam_api.c	1 Sep 2005 16:49:49 -0000
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <sys/param.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -51,6 +52,20 @@
     NULL
 };
 
+#if defined(SOCKCREDSIZE)
+#define BSDCRED		struct sockcred
+#define CRED_DATASIZE	(SOCKCREDSIZE(NGROUPS))
+#define credpid(c)	((pid_t)(-1))
+#define creduid(c)	(c->sc_euid)
+#define credgid(c)	(c->sc_egid)
+#elif defined(HAVE_CMSGCRED)
+#define BSDCRED		struct cmsgcred
+#define CRED_DATASIZE	(sizeof(struct cmsgcred))
+#define credpid(c)	(c->cmcred_pid)
+#define creduid(c)	(c->cmcred_euid)
+#define credgid(c)	(c->cmcred_groups[0])
+#endif
+
 #ifdef GAMIN_DEBUG_API
 int FAMDebug(FAMConnection *fc, const char *filename, FAMRequest * fr,
              void *userData);
@@ -307,12 +322,6 @@
 	goto cleanup;
     }
 #endif
-    if (st.st_mode & (S_IRWXG|S_IRWXO)) {
-	gam_error(DEBUG_INFO,
-		  "Socket %s has wrong permissions\n",
-		  path);
-	goto cleanup;
-    }
     /*
      * Looks good though binding may fail due to an existing server
      */
@@ -372,6 +381,18 @@
     }
     strncpy(&addr.sun_path[0], path, (sizeof(addr) - 4) - 1);
 #endif
+#if defined(BSDCRED) && defined(LOCAL_CREDS)
+    /* Set the socket to receive credentials. */
+    {
+        int on = 1;
+
+        if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof(on)) < 0) {
+            gam_error(DEBUG_INFO,
+                      "Unable to setsockopt() LOCAL_CREDS on %d\n", fd);
+            return(-1);
+	}
+    }
+#endif
 
     if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         if (retries == 0) {
@@ -419,37 +440,35 @@
 static int
 gamin_write_credential_byte(int fd)
 {
-    char data[2] = { 0, 0 };
-    int written;
-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
-    struct {
-	    struct cmsghdr hdr;
-	    struct cmsgcred cred;
-    } cmsg;
-    struct iovec iov;
     struct msghdr msg;
+    struct iovec iov;
+    char data = 0;
+    int written;
 
-    iov.iov_base = &data[0];
-    iov.iov_len = 1;
+#if defined(BSDCRED) && !defined(LOCAL_CREDS)
+    struct cmsghdr *cmsg;
+    char cmsgbuf[CMSG_SPACE(CRED_DATASIZE)];
+#endif
+
+    iov.iov_base = &data;
+    iov.iov_len = sizeof(data);
 
     memset (&msg, 0, sizeof (msg));
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
 
-    msg.msg_control = &cmsg;
-    msg.msg_controllen = sizeof (cmsg);
-    memset (&cmsg, 0, sizeof (cmsg));
-    cmsg.hdr.cmsg_len = sizeof (cmsg);
-    cmsg.hdr.cmsg_level = SOL_SOCKET;
-    cmsg.hdr.cmsg_type = SCM_CREDS;
+#if defined(BSDCRED) && !defined(LOCAL_CREDS)
+    memset(cmsgbuf, 0, sizeof(cmsgbuf));
+    msg.msg_control = (void *)cmsgbuf;
+    msg.msg_controllen = sizeof(cmsgbuf);
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = CMSG_LEN(CRED_DATASIZE);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_CREDS;
 #endif
 
 retry:
-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
     written = sendmsg(fd, &msg, 0);
-#else
-    written = write(fd, &data[0], 1);
-#endif
     if (written < 0) {
         if (errno == EINTR)
             goto retry;
@@ -457,7 +476,7 @@
                   "Failed to write credential bytes to socket %d\n", fd);
         return (-1);
     }
-    if (written != 1) {
+    if (written != iov.iov_len) {
         gam_error(DEBUG_INFO, "Wrote %d credential bytes to socket %d\n",
                   written, fd);
         return (-1);
@@ -646,38 +665,22 @@
     uid_t c_uid, s_uid;
     gid_t c_gid;
 
-#ifdef HAVE_CMSGCRED
-    struct {
-	    struct cmsghdr hdr;
-	    struct cmsgcred cred;
-    } cmsg;
-#endif
-
-    s_uid = getuid();
-
-#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
-    /* Set the socket to receive credentials on the next message */
-    {
-        int on = 1;
-
-        if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof(on)) < 0) {
-            gam_error(DEBUG_INFO, "Unable to set LOCAL_CREDS socket option\n");
-            return(-1);
-        }
-    }
+#if defined(BSDCRED)
+    struct cmsghdr *cmsg;
+    char cmsgbuf[CMSG_SPACE(CRED_DATASIZE)];
 #endif
 
     iov.iov_base = &buf;
-    iov.iov_len = 1;
+    iov.iov_len = sizeof(buf);
 
     memset(&msg, 0, sizeof(msg));
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
 
-#ifdef HAVE_CMSGCRED
-    memset(&cmsg, 0, sizeof(cmsg));
-    msg.msg_control = &cmsg;
-    msg.msg_controllen = sizeof(cmsg);
+#if defined(BSDCRED)
+    memset(cmsgbuf, 0, sizeof(cmsgbuf));
+    msg.msg_control = (void *)cmsgbuf;
+    msg.msg_controllen = sizeof(cmsgbuf);
 #endif
 
 retry:
@@ -688,13 +691,23 @@
         GAM_DEBUG(DEBUG_INFO, "Failed to read credentials byte on %d\n", fd);
         goto failed;
     }
-
-    if (buf != '\0') {
+    if (buf != 0) {
         GAM_DEBUG(DEBUG_INFO, "Credentials byte was not nul on %d\n", fd);
         goto failed;
     }
-#ifdef HAVE_CMSGCRED
-    if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
+#if defined(BSDCRED)
+    if (msg.msg_controllen == 0) {
+        GAM_DEBUG(DEBUG_INFO,
+                  "No control message received over recvmsg()\n");
+        goto failed;
+    }
+    if ((msg.msg_flags & MSG_CTRUNC) != 0) {
+        GAM_DEBUG(DEBUG_INFO,
+                  "Lost control message data over recvmsg()\n");
+        goto failed;
+    }
+    cmsg = CMSG_FIRSTHDR(&msg);
+    if (cmsg->cmsg_type != SCM_CREDS) {
         GAM_DEBUG(DEBUG_INFO,
                   "Message from recvmsg() was not SCM_CREDS\n");
         goto failed;
@@ -704,7 +717,7 @@
     GAM_DEBUG(DEBUG_INFO, "read credentials byte\n");
 
     {
-#ifdef SO_PEERCRED
+#if defined(SO_PEERCRED)
         struct ucred cr;
         socklen_t cr_len = sizeof(cr);
 
@@ -719,17 +732,19 @@
                       fd, cr_len, (int) sizeof(cr));
             goto failed;
         }
-#elif defined(HAVE_CMSGCRED)
-        c_pid = cmsg.cred.cmcred_pid;
-        c_uid = cmsg.cred.cmcred_euid;
-        c_gid = cmsg.cred.cmcred_groups[0];
-#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+#elif defined(BSDCRED)
+        BSDCRED *cr = (BSDCRED *)CMSG_DATA(cmsg);
+        c_pid = credpid(cr);
+        c_uid = creduid(cr);
+        c_gid = credgid(cr);
+#else
         GAM_DEBUG(DEBUG_INFO,
                   "Socket credentials not supported on this OS\n");
         goto failed;
 #endif
     }
 
+    s_uid = getuid();
     if (s_uid != c_uid) {
         GAM_DEBUG(DEBUG_INFO,
                   "Credentials check failed: s_uid %d, c_uid %d\n",
Index: server/gam_channel.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_channel.c,v
retrieving revision 1.21
diff -u -r1.21 gam_channel.c
--- server/gam_channel.c	9 Aug 2005 16:19:15 -0000	1.21
+++ server/gam_channel.c	1 Sep 2005 16:49:49 -0000
@@ -3,6 +3,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <glib.h>
+#include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/un.h>
@@ -12,6 +13,20 @@
 #include "gam_channel.h"
 #include "gam_protocol.h"
 
+#if defined(SOCKCREDSIZE)
+#define BSDCRED	struct sockcred
+#define CRED_DATASIZE	(SOCKCREDSIZE(NGROUPS))
+#define credpid(c)	((pid_t)(-1))
+#define creduid(c)	(c->sc_euid)
+#define credgid(c)	(c->sc_egid)
+#elif defined(HAVE_CMSGCRED)
+#define BSDCRED	struct cmsgcred
+#define CRED_DATASIZE	(sizeof(struct cmsgcred))
+#define credpid(c)	(c->cmcred_pid)
+#define creduid(c)	(c->cmcred_euid)
+#define credgid(c)	(c->cmcred_groups[0])
+#endif
+
 /* #define CHANNEL_VERBOSE_DEBUGGING */
 /************************************************************************
  *									*
@@ -28,37 +43,35 @@
 static gboolean
 gam_client_conn_send_cred(int fd)
 {
-    char data[2] = { 0, 0 };
-    int written;
-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
-    struct {
-	    struct cmsghdr hdr;
-	    struct cmsgcred cred;
-    } cmsg;
-    struct iovec iov;
     struct msghdr msg;
+    struct iovec iov;
+    char data = 0;
+    int written;
+
+#if defined(BSDCRED) && !defined(LOCAL_CREDS)
+    struct cmsghdr *cmsg;
+    char cmsgbuf[CMSG_SPACE(CRED_DATASIZE)];
+#endif
 
-    iov.iov_base = &data[0];
-    iov.iov_len = 1;
+    iov.iov_base = &data;
+    iov.iov_len = sizeof(data);
 
     memset (&msg, 0, sizeof (msg));
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
 
-    msg.msg_control = &cmsg;
-    msg.msg_controllen = sizeof (cmsg);
-    memset (&cmsg, 0, sizeof (cmsg));
-    cmsg.hdr.cmsg_len = sizeof (cmsg);
-    cmsg.hdr.cmsg_level = SOL_SOCKET;
-    cmsg.hdr.cmsg_type = SCM_CREDS;
+#if defined(BSDCRED) && !defined(LOCAL_CREDS)
+    memset(cmsgbuf, 0, CMSG_SPACE(CRED_DATASIZE));
+    msg.msg_control = (void *)cmsgbuf;
+    msg.msg_controllen = CMSG_LEN(CRED_DATASIZE);
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = CMSG_LEN(CRED_DATASIZE);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_CREDS;
 #endif
 
 retry:
-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
     written = sendmsg(fd, &msg, 0);
-#else
-    written = write(fd, &data[0], 1);
-#endif
     if (written < 0) {
         if (errno == EINTR)
             goto retry;
@@ -66,7 +79,7 @@
 		  "Failed to write credential bytes to socket %d\n", fd);
 	return (-1);
     }
-    if (written != 1) {
+    if (written != iov.iov_len) {
 	gam_error(DEBUG_INFO, "Wrote %d credential bytes to socket %d\n",
 		  written, fd);
 	return (-1);
@@ -94,38 +107,22 @@
     uid_t c_uid, s_uid;
     gid_t c_gid;
 
-#ifdef HAVE_CMSGCRED
-    struct {
-	    struct cmsghdr hdr;
-	    struct cmsgcred cred;
-    } cmsg;
-#endif
-
-    s_uid = getuid();
-
-#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
-    /* Set the socket to receive credentials on the next message */
-    {
-        int on = 1;
-
-        if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof(on)) < 0) {
-            gam_error(DEBUG_INFO, "Unable to set LOCAL_CREDS socket option\n");
-            return FALSE;
-        }
-    }
+#if defined(BSDCRED)
+    struct cmsghdr *cmsg;
+    char cmsgbuf[CMSG_SPACE(CRED_DATASIZE)];
 #endif
 
     iov.iov_base = &buf;
-    iov.iov_len = 1;
+    iov.iov_len = sizeof(buf);
 
     memset(&msg, 0, sizeof(msg));
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
 
-#ifdef HAVE_CMSGCRED
-    memset(&cmsg, 0, sizeof(cmsg));
-    msg.msg_control = &cmsg;
-    msg.msg_controllen = sizeof(cmsg);
+#if defined(BSDCRED)
+    memset(cmsgbuf, 0, sizeof(cmsgbuf));
+    msg.msg_control = (void *)cmsgbuf;
+    msg.msg_controllen = sizeof(cmsgbuf);
 #endif
 
   retry:
@@ -136,13 +133,23 @@
         GAM_DEBUG(DEBUG_INFO, "Failed to read credentials byte on %d\n", fd);
         goto failed;
     }
-
-    if (buf != '\0') {
+    if (buf != 0) {
         GAM_DEBUG(DEBUG_INFO, "Credentials byte was not nul on %d\n", fd);
         goto failed;
     }
-#ifdef HAVE_CMSGCRED
-    if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
+#if defined(BSDCRED)
+    if (msg.msg_controllen == 0) {
+        GAM_DEBUG(DEBUG_INFO,
+                  "No control message received over recvmsg()\n");
+        goto failed;
+    }
+    if ((msg.msg_flags & MSG_CTRUNC) != 0) {
+        GAM_DEBUG(DEBUG_INFO,
+                  "Lost control message data over recvmsg()\n");
+        goto failed;
+    }
+    cmsg = CMSG_FIRSTHDR(&msg);
+    if (cmsg->cmsg_type != SCM_CREDS) {
         GAM_DEBUG(DEBUG_INFO,
                   "Message from recvmsg() was not SCM_CREDS\n");
         goto failed;
@@ -152,7 +159,7 @@
     GAM_DEBUG(DEBUG_INFO, "read credentials byte\n");
 
     {
-#ifdef SO_PEERCRED
+#if defined(SO_PEERCRED)
         struct ucred cr;
         socklen_t cr_len = sizeof(cr);
 
@@ -167,17 +174,19 @@
                       fd, cr_len, (int) sizeof(cr));
             goto failed;
         }
-#elif defined(HAVE_CMSGCRED)
-	c_pid = cmsg.cred.cmcred_pid;
-	c_uid = cmsg.cred.cmcred_euid;
-	c_gid = cmsg.cred.cmcred_groups[0];
-#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+#elif defined(BSDCRED)
+        BSDCRED *cr = (BSDCRED *)CMSG_DATA(cmsg);
+        c_pid = credpid(cr);
+        c_uid = creduid(cr);
+        c_gid = credgid(cr);
+#else
         GAM_DEBUG(DEBUG_INFO,
                   "Socket credentials not supported on this OS\n");
         goto failed;
 #endif
     }
 
+    s_uid = getuid();
     if (s_uid != c_uid) {
         GAM_DEBUG(DEBUG_INFO,
                   "Credentials check failed: s_uid %d, c_uid %d\n",
@@ -551,12 +560,6 @@
 	goto cleanup;
     }
 #endif
-    if (st.st_mode & (S_IRWXG|S_IRWXO)) {
-	gam_error(DEBUG_INFO,
-		  "Socket %s has wrong permissions\n",
-		  path);
-	goto cleanup;
-    }
     /*
      * Looks good though binding may fail due to an existing server
      */
@@ -645,6 +648,18 @@
     }
     strncpy(&addr.sun_path[0], path, (sizeof(addr) - 4) - 1);
     umask(0077);
+#endif
+#if defined(BSDCRED) && defined(LOCAL_CREDS)
+    /* Set the socket to receive credentials. */
+    {
+        int on = 1;
+
+        if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof(on)) < 0) {
+            gam_error(DEBUG_INFO,
+                      "Unable to setsockopt() LOCAL_CREDS on %d\n", fd);
+            return(-1);
+        }
+    }
 #endif
 
     if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Index: server/gam_kqueue.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_kqueue.c,v
retrieving revision 1.6
diff -u -r1.6 gam_kqueue.c
--- server/gam_kqueue.c	10 Aug 2005 21:59:58 -0000	1.6
+++ server/gam_kqueue.c	1 Sep 2005 16:49:49 -0000
@@ -326,7 +326,7 @@
 static gboolean
 gam_kqueue_get_uint_sysctl (const char *name, unsigned int *value)
 {
-  unsigned int value_len = sizeof(*value);
+  size_t value_len = sizeof(*value);
 
   if (sysctlbyname(name, value, &value_len, (void *)NULL, 0) < 0)
     {
@@ -1135,8 +1135,10 @@
 
   if (! gam_kqueue_get_uint_sysctl("kern.maxfiles", &maxfiles))
     return FALSE;
+#if defined(KERN_MAXFILESPERPROC)
   if (! gam_kqueue_get_uint_sysctl("kern.maxfilesperproc", &maxfilesperproc))
     return FALSE;
+#endif
 
   /*
    * We make sure to:
@@ -1145,9 +1147,13 @@
    */
 
   maxfiles *= CFG_GLOBAL_FILE_RESERVE_RATIO;
+#if defined(KERN_MAXFILESPERPROC)
   maxfilesperproc = maxfilesperproc > CFG_SELF_FILE_RESERVE
     ? maxfilesperproc - CFG_SELF_FILE_RESERVE
     : 0;
+#else
+  maxfilesperproc = maxfiles;
+#endif
 
   max_open_files = MIN(maxfiles, maxfilesperproc);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]