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