Skip to content

Commit f6473b4

Browse files
buzzqwclaude
andcommitted
fix(rdp): fix broken success-path handling, add cert trust, real home dir, wire up multimon
- RdpEmbedWidget._avvia_rdp: the post-launch bookkeeping (start timestamp, PID log, wiring the process stdout to the log view) was misplaced inside an except block that only runs on Popen failure, followed by a second, unreachable except clause. On every normal (successful) internal RDP connection this meant _t_avvio stayed None forever, so _monitor_proc() could never tell a fast connection failure from a normal session end, and the live xfreerdp output was never shown in the log view. Moved the bookkeeping to run after a successful launch and merged the two excepts into one. - xfreerdp/xfreerdp3 command builders (session_command.py preview, rdp_widget.py external and embedded paths) now add /cert:tofu. Previously no /cert: option was set, so a first connection to a host with a self-signed/untrusted certificate (the norm for most RDP hosts) could consume the piped stdin meant for the password on the certificate prompt instead, breaking auth. - Drive redirection now shares the real user home (os.path.expanduser) instead of the hardcoded "/home" (which exposes every local user's home directory on the share, not just the current user's). - rdp_monitor_mode/rdp_monitor_ids were only honored by the read-only command preview shown in the session editor; the two builders that actually launch xfreerdp never read them, so multi-monitor selection silently did nothing. Both now apply /multimon or /monitors:<ids>. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 7eae2c1 commit f6473b4

3 files changed

Lines changed: 72 additions & 17 deletions

File tree

gtk3/rdp_widget.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ def _avvia_rdp(self):
180180
domain = p.get("rdp_domain", "").strip()
181181
clips = p.get("redirect_clipboard", True)
182182
drives = p.get("redirect_drives", False)
183+
mon_mode = p.get("rdp_monitor_mode", "single")
184+
mon_ids = p.get("rdp_monitor_ids", "0").strip()
183185
self._rdp_host = host
184186

185187
# rdesktop: embedding nativo con -X (no polling)
@@ -205,7 +207,7 @@ def _avvia_rdp(self):
205207
h_init = max(alloc.height - 30, 768)
206208

207209
args = [client, f"/v:{host}:{port}",
208-
f"/w:{w_init}", f"/h:{h_init}"]
210+
f"/w:{w_init}", f"/h:{h_init}", "/cert:tofu"]
209211
if freerdp_ver >= 3:
210212
args.append("/dynamic-resolution")
211213
if user: args.append(f"/u:{user}")
@@ -216,7 +218,11 @@ def _avvia_rdp(self):
216218
args.append("/auth-pkg-list:ntlm")
217219
if pwd: args.append("/from-stdin")
218220
if clips: args.append("/clipboard")
219-
if drives: args.append("/drive:home,/home")
221+
if drives: args.append(f"/drive:home,{os.path.expanduser('~')}")
222+
if mon_mode == "all":
223+
args.append("/multimon")
224+
elif mon_mode == "custom" and mon_ids:
225+
args.append(f"/monitors:{mon_ids}")
220226

221227
cmd_display = " ".join(args)
222228
if pwd:
@@ -254,19 +260,19 @@ def _avvia_rdp(self):
254260
_get_log(__name__).debug("Invio password RDP fallito: %s", e)
255261
except Exception as e:
256262
_get_log(__name__).debug("Avvio RDP fallito: %s", e)
257-
self._t_avvio = datetime.datetime.now()
258-
from pcm_logging import get_logger
259-
get_logger(__name__).info("Avviato %s PID=%s", client, self._proc.pid)
260-
if hasattr(self, "_log_view"):
261-
GLib.io_add_watch(
262-
self._proc.stdout.fileno(),
263-
GLib.IO_IN | GLib.IO_HUP | GLib.IO_ERR,
264-
self._on_rdp_output,
265-
)
266-
except Exception as e:
267263
self._mostra_errore(str(e))
268264
return False
269265

266+
self._t_avvio = datetime.datetime.now()
267+
from pcm_logging import get_logger
268+
get_logger(__name__).info("Avviato %s PID=%s", client, self._proc.pid)
269+
if hasattr(self, "_log_view"):
270+
GLib.io_add_watch(
271+
self._proc.stdout.fileno(),
272+
GLib.IO_IN | GLib.IO_HUP | GLib.IO_ERR,
273+
self._on_rdp_output,
274+
)
275+
270276
self._poll_attempts = 0
271277
if self._open_mode == "internal":
272278
self._poll_source = GLib.timeout_add(500, self._cerca_e_reparenta)
@@ -658,6 +664,8 @@ def _build_freerdp_cmd(profilo: dict) -> list[str]:
658664
clips = profilo.get("redirect_clipboard", True)
659665
drives = profilo.get("redirect_drives", False)
660666
fs = profilo.get("fullscreen", False)
667+
mon_mode = profilo.get("rdp_monitor_mode", "single")
668+
mon_ids = profilo.get("rdp_monitor_ids", "0").strip()
661669

662670
if client == "rdesktop":
663671
args = ["rdesktop", "-a16"]
@@ -670,7 +678,7 @@ def _build_freerdp_cmd(profilo: dict) -> list[str]:
670678

671679
# xfreerdp / xfreerdp3
672680
ver = _freerdp_major_version(client)
673-
args = [client, f"/v:{host}:{port}"]
681+
args = [client, f"/v:{host}:{port}", "/cert:tofu"]
674682
if ver >= 3:
675683
args.append("/dynamic-resolution")
676684
if user: args.append(f"/u:{user}")
@@ -680,5 +688,9 @@ def _build_freerdp_cmd(profilo: dict) -> list[str]:
680688
if pwd: args.append("/from-stdin")
681689
if fs: args.append("/f")
682690
if clips: args.append("/clipboard")
683-
if drives: args.append("/drive:home,/home")
691+
if drives: args.append(f"/drive:home,{os.path.expanduser('~')}")
692+
if mon_mode == "all":
693+
args.append("/multimon")
694+
elif mon_mode == "custom" and mon_ids:
695+
args.append(f"/monitors:{mon_ids}")
684696
return args

gtk3/session_command.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,15 @@ def _build_rdp(p: dict) -> str:
324324
exe = _get_tool(client)
325325

326326
if client in ("xfreerdp", "xfreerdp3"):
327-
args = [f"/v:{_q(f'{host}:{port}')}"]
327+
args = [f"/v:{_q(f'{host}:{port}')}", "/cert:tofu"]
328328
if user: args.append(f"/u:{_q(user)}")
329-
if domain: args.append(f"/d:{_q(domain)}")
329+
if domain:
330+
args.append(f"/d:{_q(domain)}")
331+
args.append("/auth-pkg-list:ntlm")
330332
if pwd: args.append("/from-stdin")
331333
if p.get("fullscreen"): args.append("/f")
332334
if p.get("redirect_clipboard"): args.append("/clipboard")
333-
if p.get("redirect_drives"): args.append("/drive:home,/home")
335+
if p.get("redirect_drives"): args.append(f"/drive:home,{_q(os.path.expanduser('~'))}")
334336
mon_mode = p.get("rdp_monitor_mode", "single")
335337
if mon_mode == "all":
336338
args.append("/multimon")

gtk3/tests/test_session_command.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,44 @@ def test_rdesktop_password_is_not_added_to_argv(self, monkeypatch):
191191
"rdp_client": "rdesktop", "host": "rdp.example", "password": "secret",
192192
})
193193
assert not any(arg.startswith("-p") for arg in args)
194+
195+
def test_xfreerdp_uses_cert_tofu_not_full_ignore(self, monkeypatch):
196+
"""/cert:tofu valida comunque il certificato dopo il primo collegamento;
197+
non deve mai regredire a /cert:ignore (bypass totale)."""
198+
import rdp_widget
199+
monkeypatch.setattr(rdp_widget, "_freerdp_major_version", lambda c: 3)
200+
args = _build_freerdp_cmd({
201+
"rdp_client": "xfreerdp3", "host": "rdp.example", "password": "secret",
202+
})
203+
assert "/cert:tofu" in args
204+
assert "/cert:ignore" not in args
205+
206+
def test_xfreerdp_drive_redirect_uses_real_home(self, monkeypatch):
207+
"""La condivisione unità deve puntare alla home dell'utente corrente,
208+
non alla cartella /home che contiene le home di tutti gli utenti."""
209+
import rdp_widget
210+
monkeypatch.setattr(rdp_widget, "_freerdp_major_version", lambda c: 3)
211+
args = _build_freerdp_cmd({
212+
"rdp_client": "xfreerdp3", "host": "rdp.example",
213+
"redirect_drives": True,
214+
})
215+
drive_arg = next(a for a in args if a.startswith("/drive:"))
216+
assert drive_arg == f"/drive:home,{os.path.expanduser('~')}"
217+
assert drive_arg != "/drive:home,/home"
218+
219+
def test_xfreerdp_multimon_reaches_real_command(self, monkeypatch):
220+
"""rdp_monitor_mode deve incidere sul comando davvero eseguito
221+
(non solo sull'anteprima mostrata nell'editor sessione)."""
222+
import rdp_widget
223+
monkeypatch.setattr(rdp_widget, "_freerdp_major_version", lambda c: 3)
224+
args = _build_freerdp_cmd({
225+
"rdp_client": "xfreerdp3", "host": "rdp.example",
226+
"rdp_monitor_mode": "all",
227+
})
228+
assert "/multimon" in args
229+
230+
args = _build_freerdp_cmd({
231+
"rdp_client": "xfreerdp3", "host": "rdp.example",
232+
"rdp_monitor_mode": "custom", "rdp_monitor_ids": "0,1",
233+
})
234+
assert "/monitors:0,1" in args

0 commit comments

Comments
 (0)