diff --git a/src/cockpit/beiboot.py b/src/cockpit/beiboot.py index 3e2583e19039..79f04a6ee169 100644 --- a/src/cockpit/beiboot.py +++ b/src/cockpit/beiboot.py @@ -126,7 +126,7 @@ def shutdown(self) -> None: self.peer.close() -class AuthorizeResponder(ferny.InteractionResponder): +class AuthorizeResponder(ferny.AskpassHandler): commands = ('ferny.askpass', 'cockpit.report-exists') router: Router @@ -184,8 +184,7 @@ def __init__(self, router: Router, destination: str, args: argparse.Namespace): async def do_connect_transport(self) -> None: beiboot_helper = BridgeBeibootHelper(self) - agent = ferny.InteractionAgent(AuthorizeResponder(self.router)) - agent.add_handler(beiboot_helper) + agent = ferny.InteractionAgent([AuthorizeResponder(self.router), beiboot_helper]) # We want to run a python interpreter somewhere... cmd: Sequence[str] = ('python3', '-ic', '# cockpit-bridge') diff --git a/src/cockpit/polkit.py b/src/cockpit/polkit.py index 1e3f85fbb45c..b59a6a2c7e44 100644 --- a/src/cockpit/polkit.py +++ b/src/cockpit/polkit.py @@ -22,7 +22,7 @@ import pwd from typing import Dict, List, Sequence, Tuple -from cockpit._vendor.ferny import InteractionResponder +from cockpit._vendor.ferny import AskpassHandler from cockpit._vendor.systemd_ctypes import Variant, bus # that path is valid on at least Debian, Fedora/RHEL, and Arch @@ -43,7 +43,7 @@ # mapping, but that method is not available for Python 3.6 yet. class org_freedesktop_PolicyKit1_AuthenticationAgent(bus.Object): - def __init__(self, responder: InteractionResponder): + def __init__(self, responder: AskpassHandler): super().__init__() self.responder = responder @@ -125,7 +125,7 @@ class PolkitAgent: Use this as a context manager to ensure that the agent gets unregistered again. """ - def __init__(self, responder: InteractionResponder): + def __init__(self, responder: AskpassHandler): self.responder = responder self.agent_slot = None diff --git a/src/cockpit/remote.py b/src/cockpit/remote.py index b1cbaf48d80d..c4facc364934 100644 --- a/src/cockpit/remote.py +++ b/src/cockpit/remote.py @@ -30,7 +30,7 @@ logger = logging.getLogger(__name__) -class PasswordResponder(ferny.InteractionResponder): +class PasswordResponder(ferny.AskpassHandler): PASSPHRASE_RE = re.compile(r"Enter passphrase for key '(.*)': ") password: Optional[str] @@ -104,7 +104,7 @@ async def do_connect_transport(self) -> None: logger.debug('connecting to host %s failed: %s', host, exc) raise PeerError('no-host', error='no-host', message=str(exc)) from exc - except ferny.HostKeyError as exc: + except ferny.SshHostKeyError as exc: if responder.hostkeys_seen: # If we saw a hostkey then we can issue a detailed error message # containing the key that would need to be accepted. That will @@ -114,7 +114,7 @@ async def do_connect_transport(self) -> None: else: error_args = {} - if isinstance(exc, ferny.ChangedHostKeyError): + if isinstance(exc, ferny.SshChangedHostKeyError): error = 'invalid-hostkey' elif self.private: error = 'unknown-hostkey' @@ -126,7 +126,7 @@ async def do_connect_transport(self) -> None: type(exc), exc, self.private, responder.hostkeys_seen, error, error_args) raise PeerError(error, error=error, auth_method_results={}, **error_args) from exc - except ferny.AuthenticationError as exc: + except ferny.SshAuthenticationError as exc: logger.debug('authentication to host %s failed: %s', host, exc) results = {method: 'not-provided' for method in exc.methods} diff --git a/src/cockpit/superuser.py b/src/cockpit/superuser.py index a938c128f179..aa48706ed799 100644 --- a/src/cockpit/superuser.py +++ b/src/cockpit/superuser.py @@ -40,9 +40,9 @@ class SuperuserPeer(ConfiguredPeer): - responder: ferny.InteractionResponder + responder: ferny.AskpassHandler - def __init__(self, router: Router, config: BridgeConfig, responder: ferny.InteractionResponder): + def __init__(self, router: Router, config: BridgeConfig, responder: ferny.AskpassHandler): super().__init__(router, config) self.responder = responder @@ -54,7 +54,17 @@ async def do_connect_transport(self) -> None: else: logger.debug('connecting non-polkit superuser peer transport %r', self.args) - agent = ferny.InteractionAgent(self.responder) + responders: 'list[ferny.InteractionHandler]' = [self.responder] + + if '# cockpit-bridge' in self.args: + logger.debug('going to beiboot superuser bridge %r', self.args) + helper = BridgeBeibootHelper(self, ['--privileged']) + responders.append(helper) + stage1 = make_bootloader(helper.steps, gadgets=ferny.BEIBOOT_GADGETS).encode() + else: + stage1 = None + + agent = ferny.InteractionAgent(responders) if 'SUDO_ASKPASS=ferny-askpass' in self.env: tmpdir = context.enter_context(TemporaryDirectory()) @@ -65,11 +75,8 @@ async def do_connect_transport(self) -> None: transport = await self.spawn(self.args, env, stderr=agent, start_new_session=True) - if '# cockpit-bridge' in self.args: - logger.debug('going to beiboot superuser bridge %r', self.args) - helper = BridgeBeibootHelper(self, ['--privileged']) - agent.add_handler(helper) - transport.write(make_bootloader(helper.steps, gadgets=ferny.BEIBOOT_GADGETS).encode()) + if stage1 is not None: + transport.write(stage1) try: await agent.communicate() @@ -77,7 +84,7 @@ async def do_connect_transport(self) -> None: raise PeerError('authentication-failed', message=str(exc)) from exc -class CockpitResponder(ferny.InteractionResponder): +class CockpitResponder(ferny.AskpassHandler): commands = ('ferny.askpass', 'cockpit.send-stderr') async def do_custom_command(self, command: str, args: Tuple, fds: List[int], stderr: str) -> None: @@ -125,7 +132,7 @@ def apply_rule(self, options: JsonObject) -> Optional[Peer]: # superuser requested, but not active? That's an error. raise RoutingError('access-denied') - # ferny.InteractionResponder + # ferny.AskpassHandler async def do_askpass(self, messages: str, prompt: str, hint: str) -> Optional[str]: assert self.pending_prompt is None echo = hint == "confirm" @@ -153,7 +160,7 @@ def peer_done(self): self.current = 'none' self.peer = None - async def go(self, name: str, responder: ferny.InteractionResponder) -> None: + async def go(self, name: str, responder: ferny.AskpassHandler) -> None: if self.current != 'none': raise bus.BusError('cockpit.Superuser.Error', 'Superuser bridge already running') diff --git a/test/pytest/test_beiboot.py b/test/pytest/test_beiboot.py index cec36806c9c4..8571c02501a5 100644 --- a/test/pytest/test_beiboot.py +++ b/test/pytest/test_beiboot.py @@ -12,7 +12,7 @@ class BeibootPeer(Peer): async def do_connect_transport(self) -> None: helper = BridgeBeibootHelper(self) - agent = ferny.InteractionAgent(helper) + agent = ferny.InteractionAgent([helper]) transport = await self.spawn([sys.executable, '-iq'], env=[], stderr=agent) transport.write(bootloader.make_bootloader(helper.steps, gadgets=ferny.BEIBOOT_GADGETS).encode()) await agent.communicate() diff --git a/vendor/ferny b/vendor/ferny index 7d706d567452..c26d44452e9c 160000 --- a/vendor/ferny +++ b/vendor/ferny @@ -1 +1 @@ -Subproject commit 7d706d56745274ce9c46a2540916dced14bcbd5e +Subproject commit c26d44452e9cb82dcafa71f88032bffcd7b9fa41