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 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs