lamco-rdp-server Changelog

The full version history for lamco-rdp-server, newest first, following the Keep a Changelog structure the project uses in its repository. The current release is 1.4.4. Older detail beyond the entries reproduced here lives in the repository CHANGELOG.md.

1.4.4 (2026-07-03)

Added

Unified multi-transport accept layer. A Listener trait and AcceptDispatcher put protocol and transport binding behind one uniform interface.

  • AF_VSOCK transport for Hyper-V Enhanced Session Mode (closes #52). Tri-state config (auto, enabled, disabled) with Hyper-V DMI auto-detection. Enabled by the vsock Cargo feature.
  • WebSocket and RDCleanPath transport for browser and WASM clients, which removes the separate ws-rdp-proxy from production deployments. Enabled by the websocket Cargo feature. This transport ships experimental in 1.4.4 (not yet exercised end to end against the WASM client).
  • LISTEN_FDS multi-fd socket activation. systemd can pass TCP, Unix, vsock, and WebSocket file descriptors together to one binary; descriptors are dispatched by socket name with positional fallback.

Vulkan Video encoder. Cross-vendor H.264 encoding via VK_KHR_video_encode_h264, working on NVIDIA, Intel, and AMD GPUs with Vulkan Video driver support. Enabled by the vulkan-video Cargo feature, inside the hardware-encoding umbrella alongside VA-API and NVENC.

HTTP metrics server. Prometheus /metrics and JSON /health endpoints on a lightweight tiny-http server. Enabled by the metrics-server Cargo feature.

Session health sensor framework. A HealthSensor trait with concrete sensors for PipeWire, Portal, Mutter, EGFX, and the active encoder backend; a SensorRegistry for per-session ownership plus a snapshot collector; and closed-loop signaling where damage detection feeds encoding decisions and compositor-crash detection cascades through the session lifecycle. The GUI Status and Performance tabs surface health output alongside live damage-source, FPS, and activity telemetry.

Linux-to-Windows clipboard file copy on native installs, via initiate_file_copy with a live RDP sender wired into the FUSE read handler.

Unicode keyboard input. XKB keysym mapping for non-ASCII characters.

COSMIC pointer injection via /dev/uinput as an interim path while the COSMIC input portal matures.

PAM environment self-check. At startup the server reads the kernel no_new_privs bit from /proc/self/status; when it is set, PAM authentication is advertised as unavailable (the sgid-shadow unix_chkpwd helper cannot elevate, so every login would fail) and the server falls back loudly to the recommended auth method.

OpenH264 licensing surface. A --licenses flag prints the third-party license notices, reproducing Cisco's OpenH264 binary license in full. The license text also ships in the package, and in the Flatpak under /app/share/licenses. Cisco's attribution appears in the EGFX codec settings, where H.264 is configured.

Changed

  • Session lifecycle is now per-connection on GNOME/Mutter. A SessionLifecyclePolicy abstraction (Persistent versus PerConnection) replaces the single long-lived RemoteDesktop and ScreenCast session. Mutter Direct creates a fresh, dialog-free session on each connect and releases it on disconnect, so the server serves many sequential RDP sessions without a restart. Previously Mutter's idle timeout reaped the one session about eight seconds after a client left, with no rebuild path.
  • License: BUSL-1.1 revision. The Licensor is now Lamco Development LLC following LLC formation. The Additional Use Grant is a single conditional grant with four qualifying classes (non-profit, single server instance, non-commercial education or research, and Community Edition), and the Change Date is 2029-06-01, on which this version converts to Apache-2.0.
  • lamco-pipewire de-bundled to crates.io 0.4.4 (was a vendored copy); 0.4.4 carries the DMA-BUF negotiation fix for the zero-data root cause. xdg-desktop-portal-generic likewise de-bundled to crates.io 0.4.0.
  • MSRV is 1.89 (was 1.88), on Rust edition 2024.
  • IronRDP fork relocated to the organization-owned lamco-admin/IronRDP and curated-rebased onto upstream master. The accept path migrated to run_connection_with(stream, TransportTls::AlreadyDone), and RdpsndServerHandler split into choose_format plus start.
  • Dependency upgrades: ashpd 0.13.7 (portal notification, background, and secret features), cudarc 0.19 for NVENC, vk-video 0.3.1, and the pipewire stack advanced accordingly.
  • ZGFX compression default remains never. An interim change to always was reverted: the LZ77 variant degrades to quadratic time on already-compressed H.264 payloads and stalls the EGFX pipeline on large IDR frames.
  • EGFX gate timer is now per-connection (was per-server-uptime, which broke multi-connection scenarios), with a gate timeout for clients that never open a DVC channel.
  • libei is the default input protocol, with touch and relative-pointer support.
  • VA-API hardened: reference-frame management, rate control, triple-buffered output, and SIMD NV12 conversion.
  • gui is now a default Cargo feature. A plain cargo build --release produces both lamco-rdp-server and lamco-rdp-server-gui; packaging that already opted into gui (Debian, RPM Fusion, OBS, Flatpak) is unchanged. Headless, server-only builds must now pass --no-default-features and re-enable what they need.
  • OpenH264 on Flatpak reflects the freedesktop extension retirement. The org.freedesktop.Platform.openh264 extension is retired and absent on the 25.08 runtime, and codecs-extra (x264/ffmpeg) is not a patent-covered substitute. Software H.264 uses Cisco's binary, which the user installs separately per Cisco's license; the app does not bundle or auto-download it, and the not-found guidance now points to hardware encoding, a native package, or Cisco's release list.

Fixed

  • PAM was unusable on the hardened system service. The system unit's seccomp options imply NoNewPrivileges, which the startup self-check read as "PAM unavailable", silently downgrading auth_method=pam to unauthenticated in exactly the multi-user case where PAM matters. The system unit now joins the shadow group so pam_unix reads /etc/shadow directly, keeping the full seccomp hardening, and the self-check recognizes the direct-read path.
  • Packaged systemd units SIGSYS-killed the server at startup and made PAM authentication impossible. Both units dropped NoNewPrivileges=yes and the SystemCallFilter=~@privileged @resources deny: libpipewire's realtime scheduling setup crashed the server during PipeWire init, the @privileged deny killed pam_unix's in-process setuid, and NoNewPrivileges blocked the sgid-shadow unix_chkpwd helper and the setuid fusermount3 from elevating. The @system-service allowlist, ProtectSystem=strict, and RestrictRealtime=yes remain in place.
  • GNOME served only one RDP session before needing a restart. Root-caused to the persistent-session model colliding with Mutter's idle-timeout reaping, and fixed by the per-connection lifecycle rework plus its follow-on races: capture-node rebinding is now keyed on session re-establishment rather than PipeWire node-id equality; the pipeline no longer pauses on unserved or probe disconnects; EGFX shared handler state resets on each new connection; and Mutter clipboard signal listeners re-subscribe after re-establishment.
  • GNOME 49 input stopped working until a lazy Mutter EIS lifecycle with a correct keep-alive connection was added (closes #45). The EIS capability bind mask is now accumulated from advertised Seat::Capability events instead of a blanket union.
  • KDE Windows-to-Linux clipboard file transfer was broken because Klipper re-announced a file URI as text/plain and the cooperation handler forwarded that re-announcement, discarding the portal's block decision; SendInitiateCopy is now gated on the portal sync decision. The persistent clipboard monitor also binds ext-data-control-v1 (which KWin exposes, not wlr-data-control-v1), and Klipper empty-selection clearing is gated to KDE.
  • sway and wlroots color skew (blue rendered as brown): the portal-generic direct-frame bridge defaulted every frame to BGRx, but sway delivers Xbgr8888 (RGBx byte order) via wlr-screencopy. The bridge now honors the wl_shm capture format and swaps the R and B channels in place.
  • COSMIC delivered zero frames compared with 1.4.2; capture is now routed to the portal-generic embedded strategy via a capture-protocol gate.
  • WebSocket and RDCleanPath listener could drop a connection mid-handshake when another transport won the shared accept race. The handshake now runs in a background task off the cancellable accept path.
  • SIMD damage detection corrected on aarch64 (NEON) and AVX2; the AVX2 kernel is now runtime-dispatched so stock baseline-x86_64 packages use it instead of falling back to scalar.
  • GUI fixes: 38 text-input fields that silently discarded typed text now write back to the fields the renderer reads from; notification messages render; file dialogs degrade gracefully when no FileChooser portal is present; startup skips the wgpu hardware probe on virtual GPUs; LAMCO_GUI_SOFTWARE is honored before the GPU probe; "Stop Server" now stops a D-Bus-connected server; and log-directory writability is validated with pre-init failures classified correctly.
  • GUI failed to detect externally-started servers. The headless server now writes its PID to $XDG_RUNTIME_DIR/lamco-rdp-server.pid at startup and removes it on shutdown, so a server started via systemd, SSH, or any other launcher is visible to the GUI.
  • TLS material now self-heals at startup, after logging init, and Snap sandboxing is detected, fixing a confusing headless-start failure after a user config was removed.
  • Health monitoring no longer flags an idle static desktop as a video stall (health is driven by authoritative stream-state events, not frame timing), reports an idle capture stream as healthy between clients, and gates the EGFX channel-closed warning on an active client.
  • EGFX: V8 client support and a handler-state race (#4); uncompressed fallback, buffer-tier selection, and virgl flip; gfx_server_handle preserved under contention; egfx_needs_init reset on reconnection; OpenH264 CONSTANT_ID corrected from 1 to 0; SPS/PPS prepending removed on P-frames; and degenerate metablock rects rejected so strict RDP clients no longer disconnect.
  • Clipboard: Mutter D-Bus array-of-strings MIME parsing, double-request caching, poll-based FD reads, and FD close after selection_write_done; FUSE access/getxattr/listxattr operations implemented; all pending serials answered in Windows-to-Linux file paste; stale-format and idempotent-disconnect edge cases; and file:// URIs percent-encoded with three duplicate implementations de-duplicated.
  • EIS: pointer-absolute device separation, a RefCell panic, event timeouts, deferred activation, start_emulating, the DMA-BUF-to-MemFd fallback on virtual GPUs, a keycode offset, and capture-device regions for coordinate mapping.
  • Portal input injection recovers when the ScreenCast stream pauses (#30); virtual GPUs are detected and forced to MemFd over DMA-BUF, which was returning zero data (#43, #47).
  • Protocol and compatibility: IPv6 dual-stack listen; FreeRDP 3.x TLS negotiation (#40); auth_method=none no longer rejects clients that send credentials (#35); FUSE clipboard stale-mount cleanup on restart (#46); Hyper-V Enhanced Session Mode via AF_VSOCK (#52); and cliprdr file transfer aligned with the new auto Lock/Unlock contract.

Security

  • Startup exposure warning when auth_method=none is combined with a non-loopback listen_addr, that is, an unauthenticated RDP listener reachable on the network. The Portal still gates screen capture interactively, so this warns rather than refuses.
  • unsafe_code lints migrated to #[expect(reason = "...")] with documented justification.
  • Eliminated undefined behavior in server_process.

Previous releases

1.4.2 (2026-03-10)

DirectChannel capture and protocol routing; PAM authentication with rate limiting and packaged service files; figment-based config loading with --generate-config; compositor-aware input auto-detection (libei versus wlr); libei default input with touch and relative-pointer support; VA-API hardening; EGFX improvements (V8 bitmap fallback, per-connection gate timer, DVC gate timeout); clipboard eager-fetch for data-control providers. Fixes: V8 EGFX frame drops (#34), idle CPU spin loops (#36), silent capture failure when WAYLAND_DISPLAY is unset (#37), and FUSE mount-failure messaging (#39).

1.4.1 (2026-03-03)

Packaging maintenance release. Distribution-channel fixes (cros-libva quilt patch refresh, systemd hardening, libfuse3 runtime dependency). No application code changes from 1.4.0.

1.4.0 (2026-02-24)

Session health monitoring with a D-Bus signal relay; clipboard provider architecture built on ext-data-control-v1 and wlr-data-control-v1 with a persistent data-control monitor; view-only (ScreenCast-only) mode; OpenH264 dynamic loading of Cisco's pre-built binary; the Community Edition designation for the Flatpak and Snap distributions; and a D-Bus management interface.

Full history for 1.3.x and earlier is in the repository CHANGELOG.md (see the repository link below).

See also: Documentation, Features, Platforms, Sessions, FAQ, Download, and the per-compositor guides (GNOME/Mutter, KDE/KWin, sway/wlroots, Hyprland, COSMIC).

Repository (full CHANGELOG) →