[Libguestfs] [PATCH nbdkit v3 4/4] server: Implement nbdkit_peer_uid and nbdkit_peer_gid for FreeBSD.

Richard W.M. Jones rjones at redhat.com
Mon Oct 5 14:58:41 UTC 2020


FreeBSD has LOCAL_PEERCRED which is similar to SO_PEERCRED under
Linux.  It can only be used to read the UID and possibly the GID, but
not the PID.
---
 docs/nbdkit-plugin.pod          |  4 +--
 filters/ip/nbdkit-ip-filter.pod |  7 ++--
 configure.ac                    |  1 +
 server/public.c                 | 64 ++++++++++++++++++++++++++++++---
 tests/test-ip-filter-gid.sh     |  8 +++--
 tests/test-ip-filter-uid.sh     |  8 +++--
 6 files changed, 76 insertions(+), 16 deletions(-)

diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index e1f10984..ee7b7e3a 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -1650,7 +1650,7 @@ C<nbdkit_error> is called and this call returns C<-1>.
 
 =head2 C<nbdkit_peer_uid>
 
-(nbdkit E<ge> 1.24, Linux only)
+(nbdkit E<ge> 1.24)
 
  int64_t nbdkit_peer_uid (void);
 
@@ -1662,7 +1662,7 @@ called and this call returns C<-1>.
 
 =head2 C<nbdkit_peer_gid>
 
-(nbdkit E<ge> 1.24, Linux only)
+(nbdkit E<ge> 1.24)
 
  int64_t nbdkit_peer_gid (void);
 
diff --git a/filters/ip/nbdkit-ip-filter.pod b/filters/ip/nbdkit-ip-filter.pod
index d7e0666b..3e63fd28 100644
--- a/filters/ip/nbdkit-ip-filter.pod
+++ b/filters/ip/nbdkit-ip-filter.pod
@@ -17,7 +17,6 @@ if these are not available.
 
 nbdkit E<ge> 1.24 added the ability to filter clients connecting over
 local Unix domain sockets by client process ID, user ID and group ID.
-This currently only works on Linux.
 
 =head1 EXAMPLES
 
@@ -128,14 +127,14 @@ could add it as an additional check.
 
 =item B<uid:>UID
 
-(nbdkit E<ge> 1.24, Linux only)
+(nbdkit E<ge> 1.24)
 
 This matches the numeric user ID C<UID>, if the client connects over a
 Unix domain socket.
 
 =item B<gid:>GID
 
-(nbdkit E<ge> 1.24, Linux only)
+(nbdkit E<ge> 1.24)
 
 This matches the numeric group ID C<GID>, if the client connects over
 a Unix domain socket.
@@ -150,8 +149,6 @@ does nothing.
 C<AF_VSOCK> connections are always unfiltered.
 
 Unix domain sockets were always unfiltered in S<nbdkit E<le> 1.22>.
-In S<nbdkit E<ge> 1.24> it is possible to apply filtering to them on
-Linux.
 
 =head1 PARAMETERS
 
diff --git a/configure.ac b/configure.ac
index 3ee4433c..8ec94ef4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -331,6 +331,7 @@ AC_CHECK_HEADERS([\
 	sys/procctl.h \
 	sys/socket.h \
 	sys/statvfs.h \
+	sys/ucred.h \
 	sys/un.h \
 	sys/wait.h])
 
diff --git a/server/public.c b/server/public.c
index 0ec33a17..9608600e 100644
--- a/server/public.c
+++ b/server/public.c
@@ -57,6 +57,14 @@
 #include <sys/socket.h>
 #endif
 
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
 #ifdef WIN32
 /* For nanosleep on Windows. */
 #include <pthread_time.h>
@@ -837,11 +845,57 @@ get_peercred (int s, int64_t *pid, int64_t *uid, int64_t *gid)
   return 0;
 }
 
-#else /* !SO_PEERCRED */
+#endif /* SO_PEERCRED */
+
+#ifdef LOCAL_PEERCRED
+
+/* FreeBSD supports LOCAL_PEERCRED and struct xucred. */
+static int
+get_peercred (int s, int64_t *pid, int64_t *uid, int64_t *gid)
+{
+  struct xucred xucred;
+  socklen_t n = sizeof xucred;
+
+  if (getsockopt (s, 0, LOCAL_PEERCRED, &xucred, &n) == -1) {
+    nbdkit_error ("getsockopt: LOCAL_PEERCRED: %m");
+    return -1;
+  }
+
+  if (xucred.cr_version != XUCRED_VERSION) {
+    nbdkit_error ("getsockopt: LOCAL_PEERCRED: "
+                  "struct xucred version (%u) "
+                  "did not match expected version (%u)",
+                  xucred.cr_version, XUCRED_VERSION);
+    return -1;
+  }
+
+  if (n != sizeof xucred) {
+    nbdkit_error ("getsockopt: LOCAL_PEERCRED: did not return full struct");
+    return -1;
+  }
+
+  if (pid)
+    nbdkit_error ("nbdkit_peer_pid is not supported on this platform");
+  if (uid && xucred.cr_uid >= 0) {
+    if (xucred.cr_uid <= INT64_MAX)
+      *uid = xucred.cr_uid;
+    else
+      nbdkit_error ("uid out of range: cannot be mapped to int64_t");
+  }
+  if (gid && xucred.cr_ngroups > 0) {
+    if (xucred.cr_gid <= INT64_MAX)
+      *gid = xucred.cr_gid;
+    else
+      nbdkit_error ("gid out of range: cannot be mapped to int64_t");
+  }
+
+  return 0;
+}
+
+#endif /* LOCAL_PEERCRED */
+
+#if !defined(SO_PEERCRED) && !defined(LOCAL_PEERCRED)
 
-/* Note this could be ported to FreeBSD, see LOCAL_PEERCRED in:
- * https://www.freebsd.org/cgi/man.cgi?query=unix&sektion=4
- */
 static int
 get_peercred (int s, int64_t *pid, int64_t *uid, int64_t *gid)
 {
@@ -850,7 +904,7 @@ get_peercred (int s, int64_t *pid, int64_t *uid, int64_t *gid)
   return -1;
 }
 
-#endif /* !SO_PEERCRED */
+#endif
 
 static int
 get_peercred_common (int64_t *pid, int64_t *uid, int64_t *gid)
diff --git a/tests/test-ip-filter-gid.sh b/tests/test-ip-filter-gid.sh
index d02407f3..6daa5f2b 100755
--- a/tests/test-ip-filter-gid.sh
+++ b/tests/test-ip-filter-gid.sh
@@ -37,8 +37,12 @@ set -e
 set -x
 
 requires qemu-img --version
-# This requires Linux.
-requires_linux_kernel_version 2.6
+
+# Not supported on Windows.
+if is_windows; then
+    echo "$0: nbdkit-ip-filter uid: not implemented on Windows"
+    exit 77
+fi
 
 nbdkit -U - -v -D ip.rules=1 --filter=ip null allow=gid:`id -g` deny=all \
        --run 'qemu-img info $nbd'
diff --git a/tests/test-ip-filter-uid.sh b/tests/test-ip-filter-uid.sh
index dc6ab679..430d6b2c 100755
--- a/tests/test-ip-filter-uid.sh
+++ b/tests/test-ip-filter-uid.sh
@@ -37,8 +37,12 @@ set -e
 set -x
 
 requires qemu-img --version
-# This requires Linux.
-requires_linux_kernel_version 2.6
+
+# Not supported on Windows.
+if is_windows; then
+    echo "$0: nbdkit-ip-filter uid: not implemented on Windows"
+    exit 77
+fi
 
 nbdkit -U - -v -D ip.rules=1 --filter=ip null allow=uid:`id -u` deny=all \
        --run 'qemu-img info $nbd'
-- 
2.27.0




More information about the Libguestfs mailing list