╭ changed ─────────────────╮ │src/serve_ssh_protocol.zig│ ╰──────────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │389 /// client logs as `Offering public key: ED25519 SHA256:…`. consumers │ │390 /// can use it as a stable per-key identity. │ │391 fingerprint: [fingerprint_len]u8, │ │392 + /// the SSH wire-format blob of that pubkey │ │393 + public_key: []const u8 = "", │ │394 closed: bool = false, │ │395 // what a SessionReader or SessionWriter actually hit. kept apart so a│ │396 // cleanup write can't replace the cause of a failed read. │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │785 } │ │786 │ │787 fn authAndRunChannels(conn: *Conn, handler: anytype) !void { │ │786 - const fingerprint = try runAuth(conn); │ │787 - try runChannelLayer(conn, &fingerprint, handler); │ │788 + const client_key = try runAuth(conn); │ │789 + defer conn.allocator.free(client_key.blob); │ │790 + try runChannelLayer(conn, &client_key, handler); │ │791 } │ │792 │ │793 /// tell the peer why we're hanging up (RFC 4253 §11.1), best effort. protocol│ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │1686 return out; │ │1687 } │ │1688 │ │1686 -fn runAuth(conn: *Conn) ![fingerprint_len]u8 { │ │1689 +/// the pubkey a client authenticated with │ │1690 +const ClientKey = struct { │ │1691 + fingerprint: [fingerprint_len]u8, │ │1692 + /// owned by the connection's allocator │ │1693 + blob: []const u8, │ │1694 +}; │ │1695 + │ │1696 +fn runAuth(conn: *Conn) !ClientKey { │ │1697 const allocator = conn.allocator; │ │1698 │ │1699 // step 1: service request for ssh-userauth → service accept│ ╰──────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1786 } │ │1787 │ │1788 try conn.writePacket(&.{&[_]u8{SSH_MSG_USERAUTH_SUCCESS}}); │ │1779 - return formatFingerprint(pubkey_blob); │ │1789 + return .{ .fingerprint = formatFingerprint(pubkey_blob), .blob = try allocator.dupe(u8, pubkey_blob) };│ │1790 } │ │1791 } │ │1792 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────╮ │1937 │ │1938 fn runChannelLayer( │ │1939 conn: *Conn, │ │1930 - fingerprint: *const [fingerprint_len]u8,│ │1940 + client_key: *const ClientKey, │ │1941 handler: anytype, │ │1942 ) !void { │ │1943 const allocator = conn.allocator; │ ╰──────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │1965 var sess = SessionCtx{ │ │1966 .conn = conn, │ │1967 .channel = ch, │ │1958 - .fingerprint = fingerprint.*, │ │1968 + .fingerprint = client_key.fingerprint, │ │1969 + .public_key = client_key.blob, │ │1970 }; │ │1971 defer sess.deinit(); │ │1972 handler.handleSession(&sess, request) catch |session_err| {│ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │2288 } │ │2289 }; │ │2290 var handler = Handler{}; │ │2280 - try runChannelLayer(&conn, &@as([fingerprint_len]u8, @splat(0)), &handler); │ │2291 + try runChannelLayer(&conn, &.{ .fingerprint = @splat(0), .blob = "" }, &handler);│ │2292 var output_reader = std.Io.Reader.fixed(writer.buffered()); │ │2293 var receiver = Cipher.init(&key, 0); │ │2294 const confirmation = try receiver.readPacket(allocator, &output_reader); │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯