]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlink: add new helper varlink_get_peer_pidref() for getting PidRef of peer
authorLennart Poettering <lennart@poettering.net>
Thu, 23 Nov 2023 17:12:44 +0000 (18:12 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 2 Jan 2024 16:57:35 +0000 (17:57 +0100)
src/shared/varlink.c
src/shared/varlink.h

index 12a27fcb8dfc43061af25d12cc50e24dd1cbf7e9..4664d6b2a67313d44120caeb5cd785812ae036d7 100644 (file)
@@ -171,6 +171,7 @@ struct Varlink {
         JsonVariant *current;
         VarlinkSymbol *current_method;
 
+        int peer_pidfd;
         struct ucred ucred;
         bool ucred_acquired:1;
 
@@ -361,6 +362,8 @@ static int varlink_new(Varlink **ret) {
                 .timeout = VARLINK_DEFAULT_TIMEOUT_USEC,
 
                 .af = -1,
+
+                .peer_pidfd = -EBADF,
         };
 
         *ret = v;
@@ -638,6 +641,8 @@ static void varlink_clear(Varlink *v) {
                 sigterm_wait(v->exec_pid);
                 v->exec_pid = 0;
         }
+
+        v->peer_pidfd = safe_close(v->peer_pidfd);
 }
 
 static Varlink* varlink_destroy(Varlink *v) {
@@ -2591,6 +2596,54 @@ int varlink_get_peer_pid(Varlink *v, pid_t *ret) {
         return 0;
 }
 
+static int varlink_acquire_pidfd(Varlink *v) {
+        assert(v);
+
+        if (v->peer_pidfd >= 0)
+                return 0;
+
+        v->peer_pidfd = getpeerpidfd(v->fd);
+        if (v->peer_pidfd < 0)
+                return v->peer_pidfd;
+
+        return 0;
+}
+
+int varlink_get_peer_pidref(Varlink *v, PidRef *ret) {
+        int r;
+
+        assert_return(v, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        /* Returns r > 0 if we acquired the pidref via SO_PEERPIDFD (i.e. if we can use it for
+         * authentication). Returns == 0 if we didn't, and the pidref should not be used for
+         * authentication. */
+
+        r = varlink_acquire_pidfd(v);
+        if (r < 0)
+                return r;
+
+        if (v->peer_pidfd < 0) {
+                pid_t pid;
+
+                r = varlink_get_peer_pid(v, &pid);
+                if (r < 0)
+                        return r;
+
+                r = pidref_set_pid(ret, pid);
+                if (r < 0)
+                        return r;
+
+                return 0; /* didn't get pidfd securely */
+        }
+
+        r = pidref_set_pidfd(ret, v->peer_pidfd);
+        if (r < 0)
+                return r;
+
+        return 1; /* got pidfd securely */
+}
+
 int varlink_set_relative_timeout(Varlink *v, usec_t timeout) {
         assert_return(v, -EINVAL);
         assert_return(timeout > 0, -EINVAL);
index c60f695be78ec77acd062b76fefa985355680a9c..ad8e9cc46d01564fb49b517efccab6ebc5d9617b 100644 (file)
@@ -4,6 +4,7 @@
 #include "sd-event.h"
 
 #include "json.h"
+#include "pidref.h"
 #include "time-util.h"
 #include "varlink-idl.h"
 
@@ -139,6 +140,7 @@ void* varlink_get_userdata(Varlink *v);
 
 int varlink_get_peer_uid(Varlink *v, uid_t *ret);
 int varlink_get_peer_pid(Varlink *v, pid_t *ret);
+int varlink_get_peer_pidref(Varlink *v, PidRef *ret);
 
 int varlink_set_relative_timeout(Varlink *v, usec_t usec);