]> git.ipfire.org Git - thirdparty/nqptp.git/commitdiff
Hoist PTP socket handling, drop privileges on OpenBSD
authorKlemens Nanni <kn@openbsd.org>
Sat, 27 Jan 2024 04:36:29 +0000 (05:36 +0100)
committerKlemens Nanni <klemens@posteo.de>
Sat, 27 Jan 2024 07:44:37 +0000 (08:44 +0100)
bind(2)ing ports below 1024 is the only privileged operation NQPTP does.

Move its code up in main() before shared memory handling such that root
privileges can be dropped immediately after it;  no currently supported
system does that, thus this should be a NOOP.

Do so on OpenBSD where shm_open(3) does not allow access to shared memory
objects by multiple UIDs, i.e. to communicate, shairport-sync and NQPTP
must create them and run as the very same user.

OpenBSD's official audio/shairport-sync user provides an rc.d(8) daemon
script that runs as `_shairport` user.

Makefile.am
nqptp-utilities.c
nqptp.c

index ff86fea02018594956f16d4b7e76c71dfbc7d753..5f1222275007be08a797726d2cb2fddf676c525a 100644 (file)
@@ -39,3 +39,8 @@ if INSTALL_FREEBSD_STARTUP
        chmod 555 /usr/local/etc/rc.d/nqptp
 endif
 endif
+
+if BUILD_FOR_OPENBSD
+# NQPTP starts as root on OpenBSD to access ports 319 and 320
+# and drops privileges to the user shairport is running as.
+endif
index cfbd1ee43b5c971ab6fb79e19c834f9363c48872..18e5a9c9a4ca5d6c2dfc92536972c3d93b286aa8 100644 (file)
@@ -106,7 +106,7 @@ void open_sockets_at_port(const char *node, uint16_t port,
   freeaddrinfo(info);
   if (sockets_opened == 0) {
     if (errno == EACCES) {
-      die("nqptp does not have permission to access port %u. It must (a) [Linux only] have been given CAP_NET_BIND_SERVICE capabilities using e.g. setcap or systemd's AmbientCapabilities, or (b) run as root.", port);
+      die("nqptp does not have permission to access port %u. It must (a) [Linux only] have been given CAP_NET_BIND_SERVICE capabilities using e.g. setcap or systemd's AmbientCapabilities, or (b) start as root.", port);
     } else {
       die("nqptp is unable to listen on port %u. The error is: %d, \"%s\".", port, errno, strerror(errno));
     }
diff --git a/nqptp.c b/nqptp.c
index 6af9495f3ca6daf65e137fb4d9c3670b82085b43..88cf9398dff5f8f9354305f5663b38969b051c13 100644 (file)
--- a/nqptp.c
+++ b/nqptp.c
 #include <sys/socket.h>
 #endif
 
+#ifdef CONFIG_FOR_OPENBSD
+#include <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+#endif
+
 #ifndef FIELD_SIZEOF
 #define FIELD_SIZEOF(t, f) (sizeof(((t *)0)->f))
 #endif
@@ -177,6 +183,10 @@ int main(int argc, char **argv) {
 
   sockets_open_stuff.sockets_open = 0;
 
+  // open PTP sockets
+  open_sockets_at_port(NULL, 319, &sockets_open_stuff);
+  open_sockets_at_port(NULL, 320, &sockets_open_stuff);
+
   epoll_fd = -1;
 
   // control-c (SIGINT) cleanly
@@ -191,6 +201,22 @@ int main(int argc, char **argv) {
   act2.sa_handler = termHandler;
   sigaction(SIGTERM, &act2, NULL);
 
+#ifdef CONFIG_FOR_OPENBSD
+  // shm_open(3) prohibits sharing between different UIDs, so nqptp must run as
+  // the same user shairport-sync does.
+  struct passwd *pw;
+  const char *shairport_user = "_shairport";
+  pw = getpwnam(shairport_user);
+  if (pw == NULL) {
+    die("unknown user %s", shairport_user);
+  }
+  if (setgroups(1, &pw->pw_gid) == -1 ||
+      setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
+      setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
+    die("cannot drop privileges to %s", shairport_user);
+  }
+#endif
+
   // open the SMI
 
   shm_fd = -1;
@@ -233,10 +259,7 @@ int main(int argc, char **argv) {
 
   char buf[BUFLEN];
 
-  // open sockets 319 and 320
-
-  open_sockets_at_port(NULL, 319, &sockets_open_stuff);
-  open_sockets_at_port(NULL, 320, &sockets_open_stuff);
+  // open control socket
   open_sockets_at_port("localhost", NQPTP_CONTROL_PORT,
                        &sockets_open_stuff); // this for messages from the client