Skip to content

v0.22.12

Choose a tag to compare

@github-actions github-actions released this 30 Sep 22:10
· 215 commits to main since this release

What's Changed

Added

  • RDP can now authenticate NLA with Kerberos instead of NTLM (issue #351) — a host whose account is in the Active Directory Protected Users group cannot log in over the embedded client: that group disables NTLM (and CredSSP-with-NTLM) domain-wide, so IronRDP's NTLM-only NLA was rejected with STATUS_ACCOUNT_RESTRICTION (0xc000006e), and the TLS-only fallback gave a black screen against a server that requires NLA.
    IronRDP already supports Kerberos for CredSSP, but RustConn hard-coded None for the Kerberos config when finalising the connection, so it only ever attempted NTLM. A new opt-in "Kerberos Authentication" switch under the RDP connection editor's Features section threads an ironrdp::connector::credssp::KerberosConfig (built from the local client hostname) into connect_finalize, so the SSPI layer negotiates Kerberos and falls back to NTLM only where the server and the local Kerberos setup permit it. It is off by default and affects the embedded IronRDP path only: Kerberos on Linux needs a working krb5 environment (a valid /etc/krb5.conf, DNS/SRV to the KDC, and a ticket via kinit). The connection editor exposes only the on/off switch — Kerberos talks to the KDC directly via the system krb5 config, which covers the common case. An MS-KKDCP KDC-proxy URL (for a KDC with no direct line of sight, typical behind an RD Gateway) is already plumbed end-to-end through KerberosConfig and persisted per connection, but there is no editor field to set it yet, so it stays None for now; a malformed proxy URL, once a field exists, is logged and dropped rather than aborting the connection, falling through to direct-KDC Kerberos. The flag is persisted per connection and covered by the existing RDP config round-trip tests.

Fixed

  • A SPICE connection's saved proxy and shared folders now actually reach the viewer — the connection editor let you store a SPICE proxy URL (the Proxmox VE tunnelling field) and one or more shared folders (webdav), and both were persisted correctly, but the launch path in window/protocols.rs that maps the stored SpiceConfig onto the runtime SpiceClientConfig never copied either field across. As a result --spice-proxy was never emitted (so Proxmox proxy tunnelling silently did nothing) and no folder shares were passed to remote-viewer, even though the arg-building code in rustconn-core::spice_client fully supports both. The mapping now threads proxy and every shared_folders entry through to the client config, so the two fields take effect on connect as the editor implies. The root cause is that the persisted and runtime SPICE configs are two independent structs kept in sync by a hand-written mapping; the image-compression field is still not mapped (it needs an enum conversion between the two types) and is left as a separate follow-up.

Security

  • CLI-tool downloads now all pass through the same checksum policy, and the "all downloads are verified" claim is corrected — the CLI download manager (Flatpak-only, for fetching helper binaries like kubectl, tsh, tailscale, boundary and hoop) documented that "all downloads are verified using SHA256 checksums", but the custom installers for those five tools never consulted the per-component ChecksumPolicy at all: they downloaded the binary and wrote it to disk chmod 0755 without any integrity check, so a MITM or a compromised CDN could substitute an arbitrary executable. The generic and cloud installers already honoured the policy; the custom path silently did not. All install paths now funnel their downloaded bytes through one shared enforce_checksum_policy helper, so behaviour is identical everywhere: a component with a pinned Static SHA256 is verified and fails hard on mismatch, a SkipLatest component (a "latest" URL with no stable published hash — which is what these five are) proceeds but is logged with a warning that the download is not integrity-verified, and a None component is refused. The module's security note is rewritten to describe this accurately rather than overclaiming blanket verification. New unit tests cover the helper for all three policy variants and a checksum mismatch.

  • Saving a credential into a nested KeePass group no longer reports success when a parent group could not be created — ensure_parent_groups in secret/status.rs, which walks a path like Groups/Production/Web and mkdirs each level via keepassxc-cli, only logged intermediate mkdir failures at debug! and always returned Ok(()). If a level failed (or the CLI wait errored), the subsequent add targeted a group that was never created, so the save appeared to succeed while the nested groups silently never appeared. It now treats success and "already exists" as fine but returns an error for any other outcome (including a mkdir that did not complete), so a genuine failure surfaces to the caller instead of being swallowed.

  • Restoring settings from a backup archive now writes each file atomically — ConfigManager::restore_from_archive unpacked each config file with a bare fs::write, unlike every other config write which goes through the atomic temp-file + fsync + rename path (write_locked) with owner-only (0600) permissions. A restore interrupted mid-write (crash, power loss) could therefore leave a half-written config on disk, and the restored files skipped the permission tightening. Since the backup files are all RustConn's own TOML (text), the restore now decodes each entry as UTF-8 and routes it through write_locked, so a restore has the same crash-safety and permissions as a normal save. Covered by a new backup/restore round-trip test.

  • Asbru-CM export no longer writes unusable entries for SPICE/Serial (and other unsupported) connections — the exporter emitted method: "SPICE" / method: "serial" for those protocols, but neither Asbru-CM nor RustConn's own Asbru importer recognises those method values (the importer's protocol match has no arm for them and skips them as "Unsupported protocol"), so the exported entries were dead on both sides. Worse, supports_protocol returned true for every protocol while its comment claimed "SSH, RDP, and VNC". The exporter now reports support honestly (SSH, ZeroTrust→SSH, RDP, VNC, Telnet, SFTP — the protocols that round-trip) and, like the MobaXterm exporter already does, skips the rest: they are counted as skipped and each produces a warning instead of a silently-broken entry. New tests cover the skip path and the corrected supports_protocol.

Changed

  • The embedded RDP client's smartcard_enabled and microphone_enabled config fields are now documented as reserved/not-yet-implemented — both were settable but had no effect: the embedded IronRDP client has no smart-card (scard) or audio-input (audin) virtual channel (handle_scard_call is a no-op), and neither field is surfaced in the GUI. Rather than remove them (which would change the config's serialized shape), their doc comments and the unused with_smartcard builder now state clearly that they are reserved and have no effect on the embedded client, so nobody mistakes them for working features. This is documentation only — no behaviour change. (FIDO2 passkey redirection, by contrast, is genuinely wired for the External FreeRDP-3.x client via the /fido flag and needs no change.)

Documentation

  • Removed a reference to a non-existent search_parallel API and corrected the PropertyType::Url doc — the search module's performance notes advised "consider using search_parallel for multi-threaded search", but no such function exists (only SearchCache and DebouncedSearchEngine, which do); the misleading bullet is removed. Separately, PropertyType::Url's doc claimed the value "can be rendered as a clickable link", but a URL custom property is currently displayed and edited exactly like Text — the doc now describes it accurately as a semantic type tag that is not yet rendered clickable.

Dependencies

  • Updated: yoke-derive 0.8.3→0.8.4 — the 0.8.3 release was yanked from crates.io (it reached the tree transitively via url → IronRDP/reqwest); the semver-compatible 0.8.4 replaces it, so the lockfile no longer pins a yanked crate.

Installation

Flatpak (Recommended)

flatpak install flathub io.github.totoshko88.RustConn

Snap

sudo snap install rustconn

Debian/Ubuntu (.deb from this release)

sudo dpkg -i rustconn_0.22.12_amd64.deb
sudo apt-get install -f  # Install dependencies if needed

Fedora (.rpm from this release)

sudo dnf install rustconn-0.22.12-1.fc44.x86_64.rpm

AppImage

chmod +x RustConn-0.22.12-x86_64.AppImage
./RustConn-0.22.12-x86_64.AppImage

macOS (Homebrew)

brew tap totoshko88/rustconn
brew install rustconn
open $(brew --prefix)/opt/rustconn/RustConn.app

All dependencies (GTK4, libadwaita, VTE, Adwaita icons) are installed automatically.
Requires macOS 13 (Ventura) or later.

OBS Repositories

Packages available at: https://build.opensuse.org/package/show/home:totoshko88:rustconn/rustconn

# Debian 13 (Trixie)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/ /' \
  | sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/Release.key \
  | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn

# Ubuntu 24.04 LTS (Noble)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/ /' \
  | sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/Release.key \
  | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn

# Ubuntu 26.04 LTS (Resolute)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/ /' \
  | sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/Release.key \
  | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn

# Fedora 44
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_44/home:totoshko88:rustconn.repo
sudo dnf install rustconn

# Fedora 43
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_43/home:totoshko88:rustconn.repo
sudo dnf install rustconn

# openSUSE Tumbleweed
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Tumbleweed/ rustconn
sudo zypper ref && sudo zypper in rustconn

# openSUSE Leap 16.0
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Leap_16.0/ rustconn
sudo zypper ref && sudo zypper in rustconn

Arch Linux (AUR)

yay -S rustconn

FreeBSD (Ports)

pkg install rustconn

Full installation guide: https://github.com/totoshko88/RustConn/blob/main/docs/INSTALL.md