]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/bus-proxyd/proxy.c
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
[thirdparty/systemd.git] / src / bus-proxyd / proxy.c
index c37b09b9c0ad33ea5b83919365fa5e8207684c1e..98222c50cc793de71bb384f93f2e816033c47145 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <string.h>
 #include <errno.h>
 #include <poll.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
-#include "log.h"
-#include "util.h"
-#include "sd-daemon.h"
 #include "sd-bus.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "bus-control.h"
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
-#include "strv.h"
-#include "bus-control.h"
-#include "set.h"
 #include "bus-xml-policy.h"
 #include "driver.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "log.h"
 #include "proxy.h"
+#include "set.h"
+#include "strv.h"
 #include "synthesize.h"
-#include "formats-util.h"
+#include "user-util.h"
+#include "util.h"
 
 static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
-        _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *b = NULL;
         int r;
 
         r = sd_bus_new(&b);
@@ -100,18 +104,24 @@ static int proxy_create_destination(Proxy *p, const char *destination, const cha
         return 0;
 }
 
-static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
-        _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
+static int proxy_create_local(Proxy *p, bool negotiate_fds) {
         sd_id128_t server_id;
+        sd_bus *b;
         int r;
 
         r = sd_bus_new(&b);
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate bus: %m");
 
-        r = sd_bus_set_fd(b, in_fd, out_fd);
-        if (r < 0)
+        r = sd_bus_set_fd(b, p->local_in, p->local_out);
+        if (r < 0) {
+                sd_bus_unref(b);
                 return log_error_errno(r, "Failed to set fds: %m");
+        }
+
+        /* The fds are now owned by the bus, and we indicate that by
+         * storing the bus object in the proxy object. */
+        p->local_bus = b;
 
         r = sd_bus_get_bus_id(p->destination_bus, &server_id);
         if (r < 0)
@@ -139,8 +149,6 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd
         if (r < 0)
                 return log_error_errno(r, "Failed to start bus client: %m");
 
-        p->local_bus = b;
-        b = NULL;
         return 0;
 }
 
@@ -224,9 +232,17 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
         bool is_unix;
         int r;
 
+        /* This takes possession/destroys the file descriptors passed
+         * in even on failure. The caller should hence forget about
+         * the fds in all cases after calling this function and not
+         * close them. */
+
         p = new0(Proxy, 1);
-        if (!p)
+        if (!p) {
+                safe_close(in_fd);
+                safe_close(out_fd);
                 return log_oom();
+        }
 
         p->local_in = in_fd;
         p->local_out = out_fd;
@@ -247,7 +263,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
         if (r < 0)
                 return r;
 
-        r = proxy_create_local(p, in_fd, out_fd, is_unix);
+        r = proxy_create_local(p, is_unix);
         if (r < 0)
                 return r;
 
@@ -257,14 +273,31 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
 
         *out = p;
         p = NULL;
+
         return 0;
 }
 
 Proxy *proxy_free(Proxy *p) {
+        ProxyActivation *activation;
+
         if (!p)
                 return NULL;
 
-        sd_bus_flush_close_unref(p->local_bus);
+        while ((activation = p->activations)) {
+                LIST_REMOVE(activations_by_proxy, p->activations, activation);
+                sd_bus_message_unref(activation->request);
+                sd_bus_slot_unref(activation->slot);
+                free(activation);
+        }
+
+        if (p->local_bus)
+                sd_bus_flush_close_unref(p->local_bus);
+        else {
+                safe_close(p->local_in);
+                if (p->local_out != p->local_in)
+                        safe_close(p->local_out);
+        }
+
         sd_bus_flush_close_unref(p->destination_bus);
         set_free_free(p->owned_names);
         free(p);
@@ -458,7 +491,7 @@ static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m,
                 (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
 
                 if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
-                        _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
+                        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *sender_creds = NULL;
 
                         /* If the message came from another legacy
                          * client, then the message creds will be
@@ -489,7 +522,7 @@ static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m,
         }
 
         if (to->is_kernel) {
-                _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
+                _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *destination_creds = NULL;
                 uid_t destination_uid = UID_INVALID;
                 gid_t destination_gid = GID_INVALID;
                 const char *destination_unique = NULL;
@@ -576,7 +609,7 @@ static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPol
 }
 
 static int process_hello(Proxy *p, sd_bus_message *m) {
-        _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
         bool is_hello;
         int r;
 
@@ -644,6 +677,10 @@ static int process_hello(Proxy *p, sd_bus_message *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
 
+        r = sd_bus_message_set_destination(n, p->destination_bus->unique_name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set destination for NameAcquired message: %m");
+
         r = bus_seal_synthetic_message(p->local_bus, n);
         if (r < 0)
                 return log_error_errno(r, "Failed to seal NameAcquired message: %m");
@@ -686,7 +723,7 @@ static int patch_sender(sd_bus *a, sd_bus_message *m) {
 }
 
 static int proxy_process_destination_to_local(Proxy *p) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         bool matched, matched_synthetic;
         int r;
 
@@ -757,19 +794,21 @@ static int proxy_process_destination_to_local(Proxy *p) {
                         return r;
 
                 /* If the peer tries to send a reply and it is
-                 * rejected with EPERM by the kernel, we ignore the
+                 * rejected with EBADSLT by the kernel, we ignore the
                  * error. This catches cases where the original
                  * method-call didn't had EXPECT_REPLY set, but the
                  * proxy-peer still sends a reply. This is allowed in
                  * dbus1, but not in kdbus. We don't want to track
                  * reply-windows in the proxy, so we simply ignore
-                 * EPERM for all replies. The only downside is, that
+                 * EBADSLT for all replies. The only downside is, that
                  * callers are no longer notified if their replies are
                  * dropped. However, this is equivalent to the
                  * caller's timeout to expire, so this should be
                  * acceptable. Nobody sane sends replies without a
                  * matching method-call, so nobody should care. */
-                if (r == -EPERM && m->reply_cookie > 0)
+
+                /* FIXME: remove -EPERM when kdbus is updated */
+                if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
                         return 1;
 
                 /* Return the error to the client, if we can */
@@ -793,7 +832,7 @@ static int proxy_process_destination_to_local(Proxy *p) {
 }
 
 static int proxy_process_local_to_destination(Proxy *p) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         int r;
 
         assert(p);
@@ -850,8 +889,8 @@ static int proxy_process_local_to_destination(Proxy *p) {
                         if (r == -EREMCHG)
                                 continue;
 
-                        /* see above why EPERM is ignored for replies */
-                        if (r == -EPERM && m->reply_cookie > 0)
+                        /* see above why EBADSLT is ignored for replies */
+                        if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
                                 return 1;
 
                         synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");