]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ssh-proxy: Support ssh machine/xxx for nspawn containers
authorDaan De Meyer <daan@amutable.com>
Thu, 19 Feb 2026 09:54:07 +0000 (10:54 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 19 Feb 2026 20:32:29 +0000 (21:32 +0100)
src/basic/stat-util.c
src/basic/stat-util.h
src/ssh-generator/ssh-proxy.c

index f50b64e48465e5670f7fe4f578c0f50121e2d200..43f82dd92680917a919fcef568f2b7548ceffa97 100644 (file)
@@ -157,6 +157,11 @@ int stat_verify_socket(const struct stat *st) {
         return 0;
 }
 
+int is_socket(const char *path) {
+        assert(!isempty(path));
+        return verify_stat_at(AT_FDCWD, path, /* follow= */ true, stat_verify_socket, /* verify= */ false);
+}
+
 int stat_verify_linked(const struct stat *st) {
         assert(st);
 
index e4138e960a3bfc867ec59db264729076ba3a5125..0e4bec513b1ad889b89867cfeb5efa3ef85ff4cb 100644 (file)
@@ -21,6 +21,7 @@ int fd_verify_symlink(int fd);
 int is_symlink(const char *path);
 
 int stat_verify_socket(const struct stat *st);
+int is_socket(const char *path);
 
 int stat_verify_linked(const struct stat *st);
 int fd_verify_linked(int fd);
index 219e523d6b366114982747cb09bbfa41f6de485e..337153787ec1d82dee1c21ab8fae70eb95d157d6 100644 (file)
@@ -11,7 +11,9 @@
 #include "log.h"
 #include "main-func.h"
 #include "path-lookup.h"
+#include "path-util.h"
 #include "socket-util.h"
+#include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
@@ -309,27 +311,65 @@ static int process_machine(const char *machine, const char *port) {
         assert(port);
 
         _cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL;
-        r = fetch_machine(machine, RUNTIME_SCOPE_USER, &result);
-        if (r == -ESRCH)
-                r = fetch_machine(machine, RUNTIME_SCOPE_SYSTEM, &result);
+        RuntimeScope scope = RUNTIME_SCOPE_USER;
+        r = fetch_machine(machine, scope, &result);
+        if (r == -ESRCH) {
+                scope = RUNTIME_SCOPE_SYSTEM;
+                r = fetch_machine(machine, scope, &result);
+        }
         if (r < 0)
                 return r;
 
-        uint32_t cid = VMADDR_CID_ANY;
+        struct {
+                uint32_t cid;
+                const char *class;
+                const char *service;
+        } p = {
+                .cid = VMADDR_CID_ANY,
+        };
 
         static const sd_json_dispatch_field dispatch_table[] = {
-                { "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, 0, 0 },
-                {}
+                { "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32,       voffsetof(p, cid),     0                 },
+                { "class",    SD_JSON_VARIANT_STRING,   sd_json_dispatch_const_string, voffsetof(p, class),   SD_JSON_MANDATORY },
+                { "service",  SD_JSON_VARIANT_STRING,   sd_json_dispatch_const_string, voffsetof(p, service), 0                 },
         };
 
-        r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &cid);
+        r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse Varlink reply: %m");
 
-        if (cid == VMADDR_CID_ANY)
+        if (streq(p.class, "container")) {
+                _cleanup_free_ char *path = NULL;
+
+                if (!streq_ptr(p.service, "systemd-nspawn"))
+                        return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Don't know how to SSH into '%s' container %s.", p.service, machine);
+
+                r = runtime_directory_generic(scope, "systemd/nspawn/unix-export", &path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to determine runtime directory: %m");
+
+                if (!path_extend(&path, machine, "ssh"))
+                        return log_oom();
+
+                r = is_socket(path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to check if '%s' exists and is a socket: %m", path);
+                if (r == 0)
+                        return log_error_errno(
+                                        SYNTHETIC_ERRNO(ENOENT),
+                                        "'%s' does not exist or is not a socket, are sshd and systemd-ssh-generator installed and enabled in the container?",
+                                        path);
+
+                return process_unix(path);
+        }
+
+        if (!streq(p.class, "vm"))
+                return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Don't know how to SSH into machine %s with class '%s'.", machine, p.class);
+
+        if (p.cid == VMADDR_CID_ANY)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Machine %s has no AF_VSOCK CID assigned.", machine);
 
-        return process_vsock_cid(cid, port);
+        return process_vsock_cid(p.cid, port);
 }
 
 static char *startswith_sep(const char *s, const char *prefix) {