Persistent remote desktop access API

Hi! I’m with the Chrome Remote Desktop team at Google, and I have some time this year to work toward a standard API for persistent remote access under Wayland, especially important given future plans to remove X11 support.

The current portals API for remote desktop is a good fit for remote support use cases, where there is a local user present to approve access for each connection and mirroring the physical displays is desired.

However, for persistent remote access, there are additional requirements that cannot be achieved through the existing portals API. Specifically:

  • One-time permission grant: The user needs to be able to grant permission to the remote desktop tool when they first set it up, and connect any time without further permission prompts. When connecting remotely to one’s own workstation, there will be no local user to approve the connection. This permission should survive automatic updates.
  • Virtual seat: It’s a security risk to have the physical seat unlock when a user connects to the workstation remotely, so there must be a way to create a virtual seat for the connection and have the desktop rendered there. The physical seat could then return to GDM.
  • Display configuration: Commonly, a user wants the virtual seat to match the monitor configuration of the machine they are connecting from for an immersive, full-screen, potentially multi-monitor setup. Thus, the remote desktop tool needs a way to configure virtual monitors, layout, and scaling factors to match the client.
  • Launching a session: If the user does not have an active session, the remote desktop tool should be able to launch one on their behalf.

While I realize the standardization of these APIs will likely happen outside of GNOME, GNOME is currently our first priority to support for Wayland remote-desktop, so I want to make sure whatever technical approach we pursue is one that would be accepted by GNOME.

I know @jadahl had some ideas about this in a previous discussion, and suggested a new xdg-spec under the org.freedesktop. prefix would be the right umbrella for this (as opposed to, e.g., a (set of) Wayland protocol extension(s) or twisting Portals to support persistent privileges), and had a rough sketch for what it could look like. (Do you still have that handy?)

I also saw that there is a new transient seat Wayland protocol extension geared toward remote use-cases, though I’m not sure if that would be useful for this particular endeavor . (The overview says, “This protocol is intended for use with virtual input protocols such as ‘virtual_keyboard_unstable_v1’ or ‘wlr_virtual_pointer_unstable_v1’”, while I have the impression that GNOME would prefer a protocol that still uses Pipewire for capture and libei for input injection.)

1 Like

So for GNOME 46, gnome-remote-desktop is gaining login screen support via GDM. The way it works is there is now a gnome-remote-desktop system service that serves as a dispatcher. When the user connects, they are redirected to a login screen session running its own gnome-remote-desktop session service (using a feature of RDP called ServerRedirection). After authentication, the session is started and the user is again redirected (using RDP ServerRedirection) to their user session.

assuming Chrome Remote Desktop has a similar redirection ability it could probably be implemented in a similar way. The GDM side of things isn’t tied to gnome-remote-desktop, so other remoting implementations should be able to use the same mechanism (I believe NiceDCV is working on an implementation as well for instance).

The basic idea is when a user connects, a system service calls org.gnome.DisplayManager.RemoteDisplayFactory.CreateRemoteDisplay(remote_id) which makes GDM start a login screen session, the display gets exported over the bus via a D-Bus ObjectManager interface. The login screen session should have a session agent running in it (started via say an autostart file). when it’s started it should coordinate with the system service, so the system service redirects the user to the login screen session using some sort of protocol specific means. When authentication completes, the newly started user session display has the same remote_id that was passed in initially at CreateRemoteDisplay time. This new session should also have a session agent running in it (either started via autostart or systemd --user service) to coordinate the handoff from the login screen session to the users session (probably by way of the system dispatcher service).

For 46 it’s either/or. A user gets a remote login or a local login. A dialog will pop up asking the user if they want to kill the other session when they try to log in twice.

For 47, the plan is to support a “hybrid” mode where a session can be started remotely or locally and connected to from the other way.

This work is being spearheaded by Joan Torres, so he’s a good person to reach out to (perhaps on #gnome-shell on matrix)

Work on creating an initial draft has started at https://gitlab.freedesktop.org/jadahl/xdg-specs/-/merge_requests/1. One of the main goals is to share as much functionality with the portals as possible, meaning e.g. libei for input and PipeWire for output.

Thanks for the info! It’s great to hear hybrid functionality is already in the works. Based on my reading, it seems like the the current work for gnome-remote-desktop and the proposed xdg spec use slightly different models, and I want to make sure I understand correctly:

gnome-remote-desktop

  • Uses private, unstable APIs, currently.
  • Runs as a system service.
  • When a user connects, they are presented with a GDM login screen and may log in as any user, which will either spawn a new session or connect to an existing one (once hybrid mode is implemented).
  • Can connect multiple times as long as logging in as different users, so different users would have a set of machine access credentials and would then log into their respective accounts using GDM?
  • Could potentially work with encrypted home directories.

XDG remote desktop spec

  • DBUS service and remote desktop tool run as user services.
  • When a user connects, the remote desktop tool calls org.freedesktop.RemoteDesktop1.CreateSession (assuming no remote connection is currently active). This will either:
    • Start a new desktop session for the user, or
    • If there is an existing desktop session, transition it to headless
  • Since it is a user service, only one connection makes sense and is allowed at once
  • Presumably there would be no GDM login step, since the service is already running as a specific user?
  • Would require linger to start at boot, and wouldn’t work for a user with an encrypted home directory until it had been unlocked.
  • Multiple users would each have there own remote desktop service.

Is that all correct?

Hi Erik.

About the draft Jonas did, that looks like what RemoteDesktop and Screencast portals do, but I don’t think that part covers starting and orchestrating headless sessions.

Based on the current GNOME approach, I’ll try to explain in an abstraction level to see how things could be for any remote solution.

I’m assuming:

  • The current RemoteDesktop and ScreenCast portals are enough for using a Wayland session.
  • A Wayland session is capable of running headless.

An overview:

  1. One daemon running as a system service to which the remote clients connect. This daemon is in charge of dispatching the remote clients which will end up displaying a headless Wayland session using the portals API.

  2. On a new connection, this system daemon (aka dispatcher) does the required authentication with the client (if wanted), and if it succeeds, creates a headless Wayland session. This Wayland session must have a service running which will get the remote client and use the portals to show the session.

  3. To hand over the remote client, connected to the system daemon, to the service running at the headless wayland session; the system daemon registers a Handover iface. And the session service uses it to get the remote client. The simple workflow for this might be 1. StartHandover, 2. TakeClientReady and 3. TakeClient.

Things to note:

  • The Handover API, is based on the RDP protocol, which has a ServerRedirection functionality. When a redirection is requested, the remote client disconnects and reconnects again to the system daemon, this way the session service can take the remote client using its corresponding Handover interface.

  • We rely on the display manager (GDM) to create headless wayland sessions, maybe in other situations that might be different. GDM exposes the org.gnome.DisplayManager.RemoteDisplayFactory.CreateRemoteDisplay method to create a headless wayland greeter. When the greeter is created, GDM registers a org.gnome.DisplayManager.RemoteDisplay iface. When the dispatcher finds a new RemoteDisplay is added, it registers its correspondent Handover iface to allow the handover mentioned before.
    After successful login at the greeter, a new headless user session is started with the session service to show remotely that session. GDM registers a RemoteDisplay iface for this session, and the dispatcher responds registering a Handover inface for that session. Here the remote client will be redirected from the greeter session to the user session.

  • As mentioned in the last point, there is a situation where the dispatcher redirects a remote client from one session to another.
    A remote client is identified with a unique id. Each RemoteDisplay registered, has this unique id too as a property. When the new RemoteDisplay is registered with the same remote client id for a new session, the dispatcher registers a new Handover iface and sets it as dst, and the old Handover iface with the same remote client id is set as src. Then the workflow of the handoff would be: 1. StartHandover (dst), 2. RedirectClient (src), 3. TakeClientReady (dst) and 4. TakeClient (dst).

I think a third party remote solution that implements a similar system daemon with a similar Handover iface, which uses the GDM ifaces mentioned; and a session service that uses that handover interface could work.

If I try to think of different desktop environments… Maybe, if the session service which shows remotely a session relies on portals, and that desktop environment implements the RemoteDesktop and ScreenCast portals and can run headlessly, that could be a start. Maybe other display managers could implement something similar to CreateRemoteDisplay and RemoteDisplay, I don’t know how much sense it has to standardise that.

All this is for the non-persistent use case. The next step I’m about to work on is on handling persistent and hybrid sessions. I don’t have much answers for that yet. I think having persistent sessions relies more on GDM and mutter, so any third-party remote solution that works like what was mentioned before shouldn’t change much.

Areas that might help in improving: hybrid-persistent sessions, improving GDM to not need a greeter (maybe plug GDM with the dispatcher to authenticate directly the remote client, it could be used kerberos which RDP might support in the future), here is a list of TODOs.

Thanks for the reply!

Even if session creation / curtaining is assumed to be handled by a different API analogous to the GDM RemoteDisplay API, there are three key pieces provided by @jadahl’s draft API and the unstable Mutter API that aren’t provided by the Portal APIs:

  • Virtual monitors: The draft API has CreateVirtualMonitor, and Mutter has RecordVirtual. As far as I can tell, the Portal APIs provides no mechanism for this, which makes sense since it is geared toward the use case where a user that is physically present is granting temporary access to their existing session.
  • Persistent access permission: As far as I understand, the draft API and the Mutter API are designed to be exposed only to trusted processes, and thus don’t require a local user to approve every access. The Portal RemoteDestop API, on the other hand, seems to explicitly disallow any persistence of permissions, and requires a local user to select what to share for each session.
  • Clipboard access: both the draft API and Mutter.RemoteDesktop have APIs for interacting with the clipboard for clipboard forwarding purposes. I don’t see anything in the Portal APIs providing that.

Portal permissions and limitations aside, what happens if the user logs into an account that doesn’t have a remote desktop user service configured? Do they get stuck due to the lack of a hand-off while the new session runs without a method of connecting to it? Is there any reason the system service couldn’t inject a process/service into the new session instead of requiring it to be configured ahead of time?

I suppose this issue can be mitigated somewhat by enabling the service in the global systemd user configuration.


Overall, to support persistent / hybrid sessions across multiple desktop environments / greeters, it sounds like we would need:

  • Each DE to implement a standard API like the one proposed by @jadahl or something else analogous to the existing unstable Mutter.{RemoteDesktop,ScreenCast} APIs that would be available in headless mode with the extra functionally needed over the existing Portal APIs.
  • Each greeter to implement something analogous to GDM’s unstable RemoteDisplay interface.
  • Some standard mechanism for a greeter to launch a desktop environment in headless mode, and to tell a supporting desktop environment to transition into or out of headless mode.

Does that sound like a reasonable summary?

I’m assuming things, since what I did was combining all the needed pieces on GNOME ecosystem to have the remote login. I haven’t played with portals

From ScreenCast interface, at least, I see the SelectSource method allows a Virtual property, maybe that is enough to make the backend create a virtual monitor. However, as I mentioned, I haven’t played with portals.

I think this might need to be addressed. Maybe add a method to get a restore_token, before calling Start. This way there’s an alternative way of getting permissions instead of using a dialog.

I think a candidate could be org.freedesktop.portal.Clipboard?

The solution for this is: GDM, on headless greeters, only allows to select sessions which in their desktop file have the property X-GDM-CanRunHeadless=true.

The system service doesn’t have privileges and it can’t start a service on other sessions on demand. The current approach is autostarting the session service when the system service is running, see sharing: Start gnome-remote-desktop --handover when gnome-remote-desktop --system is running (!342) · Merge requests · GNOME / gnome-settings-daemon · GitLab.
There’s a RFE to make systemd have that: RFE: monitor system units from user manager · Issue #3312 · systemd/systemd · GitHub

Based on the solution we did, this is the easiest thing that comes to my mind. However with the right resources and creativity, I think there could be improvements to the approach.

Tangentially related: how much work would it be to expand the GDM changes to include support X11 sessions? (Xfce is our main DE of interest after GNOME, and still relies on X11.)

The first part of the login seems like it would be the same (remote a login screen from GDM and prompt the user to kill any existing graphical session), but then GDM could launch Xvfb instead of Xorg to host the session (effectively making all X11 sessions support headless), and return the display number to the remote desktop tool.

sounds pretty straight forward to implement. mostly just small changes to gdm-x-session.c to start xvfb if its a headless session and gdm-sessions.c to make the x sessions not get filtered.

it might need a small change or two elsewhere to make sure things are plumbed right

It sounds like KDE was also considering adding some kind of persistent token mechanism to the Portal API. However, I think it might make sense to have two APIs based on how different the use cases are.

Remote assistance (supported well by the current Portal APIs) wants:

  • Explicit user consent to share
  • To allow the local user to select what to share
  • To mirror the selected existing displays / windows

Remote access wants:

  • Persistent access
  • To ensure the session is curtained or headless to prevent observation and interaction from the local console
  • Full control over the virtual monitor layout and the ability to capture all of it

While both use cases can be integrated into the same API, it feels like there would have to be enough special casing that it’s not an obvious win, especially given that the actual capture (PipeWire) and input injection (libei) will be same either way.

Okay, so if I understand correctly, the process by which the greeter is remoted is as follows:

  1. A user connects to the system GRD and authenticates with the system RDP credentials.
  2. The system daemon calls CreateRemoteDisplay on GDM.
  3. GDM launches a GNOME session for the greeter as the gdm user. It does this via dbus-run-session so as to have a separate session bus for each greeter instance.
  4. GRD is launched within the greeter session by the GSD plugin, allowing it to inherit the DBUS_SESSION_BUS_ADDRESS environment variable set by dbus-run-session.
  5. The session GRD instance connects to the system instance to negotiate a handoff of the connection.
  6. The client receives a Server Redirection PDU and reconnects to the GRD instance running in the session, which uses the Mutter APIs on the per-greeter session bus.

If this is correct, it seems having a user service enabled for the session component (even with the RFE) wouldn’t be sufficient, since it wouldn’t see the bus address environment variable.

Would it be feasible to have the GDM greeter pass the bus address back to the GDM system daemon, which could then make it available either as a return value from CreateRemoteDisplay or as a property on the RemoteDisplay object?

If not, what’s the best way for a non-GNOME service to ensure it is started in the GDM greeter session?

Thanks!

Short term the best solution is to install an xdg autostart file in /usr/share/gdm/greeter/autostart/ i think for 47 we’re going to try to add systemd DynamicUser support to gdm so each greeter gets its own dynamically created user. at that point a service file should work

Maybe a different API might work. However, I’m not an expert on Portals, and I don’t know how much effort would require that.

The curtained sessions for the hybrid use case is still something open for its implementation. I can see the headfull<->headless transition should be triggered from GDM. After that, I can’t tell yet how the process will be and how dbus will be implicated.

Yes, that’s the process. As Ray mentioned, to start a different service like g-r-d on a GDM greeter session, use the xdg autostart thing.

Hmm, I thought if a session service is started inside that session it can communicate with the dbus session daemon. At least, that’s what currently happens.

Sorry, I meant having the session component as a systemd user service wouldn’t work for the greeter. Using the xdg autostart file as suggested by @halfline should work fine, since, as I understand it, that should result in the session component running as a descendant of dbus-run-session.

That said, for more architectural flexibility in the remote access tool, and to avoid needing to install autostart files for specific greeters / desktop environments, I would like to see a future API provide a means to return the information needed to connect to the greeter session and login session back to the remote access tool’s system daemon. This may include the uid and dbus address of the session, and potentially an access token of some sort if that is deemed desirable.

Given our current architecture, we would prefer to have an isolated network process with no system access, a session process with user privileges, and a system process to manage the other processes and broker IPC. This is what we do on Windows, and it allows the network process to maintain the WebRTC connection to the client for a seamless transition from the login-screen process to the desktop-session process.

While requiring autostart doesn’t preclude this approach (if nothing else, we could have a small autostart script/binary pass the requisite information back to the system process somehow), it would be a lot easier if the system process could just get the information from the RemoteDisplay object on the system bus directly, and establishing the IPC channel is simpler if the system process can spawn the session process itself.

Sorry, I meant having the session component as a systemd user service wouldn’t work for the greeter. Using the xdg autostart file as suggested by @halfline should work fine, since, as I understand it, that should result in the session component running as a descendant of dbus-run-session.

Right and once GDM gets DynamicUser support, a regular systemd user service file should do the job for both user and login screen sessions

I would like to see a future API provide a means to return the information needed to connect to the greeter session and login session back to the remote access tool’s system daemon. This may include the uid and dbus address of the session, and potentially an access token of some sort if that is deemed desirable.

This is a generally a frowned upon practice. It’s considered bad form to have a privileged system service try to join a user session, rather than have a session agent make requests to the privileged system service. it’s sort of reverse flow and can have security ramifications. I’m not saying it can’t be done securely, or that it’s necessarily dangerous, but it’s a pattern I would personally avoid.

Having said that, if we fix GDM to have DynamicUser support then the bus address will always be a well known name (DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus)

While I agree with that for general services (e.g., it would be really weird if the NetworkManager system service tried to inject nm-applet instances into user sessions), I do think allowing the system service to spawn a child process that drops privileges to the target user for the specific use case of remote access has a number of advantages:

  • Doesn’t depend on systemd or any greeter-specific auto-start mechanism to launch the user-privileged process.
    • GNOME Remote Desktop can rely on the GNOME Settings Daemon patch to launch the user process if and only if the system daemon is running, but other remote access tools may want to equally support, e.g., a future Wayland-based XFCE session running on an OpenRC system without special cases.
  • Removes the failure mode where the user selects a session that, upon launch, doesn’t run the user service corresponding to the remote access tool.
    • Currently, if a session specifies the X-GDM-CanRunHeadless=true property, it can be depended on to launch the GNOME Remote Desktop user service, as mentioned in the previous point. However, when the user is using an arbitrary remote access tool and an arbitrary desktop environment running on an arbitrary init system, there could be any number of reasons that the launched desktop environment might fail to run the user service corresponding to the remote access tool with which the user is connecting.
  • Avoids the need to have a process for every configured remote access tool running in every session.
    • If remote access user services have to autostart as part of the session, then every session running on the system would necessarily autostart the user service for every remote access tool installed on the system. These user services would have to stay running even when not currently being used to control to the session, since the user may connect with that tool later (especially true once dynamic curtaining is supported).
    • If instead the system daemon launches the user-privileged process on demand, it would only run when a user connects, and only for the duration of the connection, similar to how SSH user processes work.
  • Potentially simpler connection hand-off / IPC channel establishment.
    • If the system service launches the user process, it can easily pass the needed file descriptors / tokens / et cetera needed to either directly transfer the connection socket or establish a secure IPC channel.
    • If the user process is launched as part of the session, the daemon has to take additional steps to expose a connectable interface and ensure the process that connects to it is the expected one.
  • Process management
    • The system service can monitor the user process, gracefully handle crashes, and terminate it on disconnection.

I’m not saying that every remote access tool should implement this approach, just that it should be possible with a hypothetical standardized solution.

Even if GDM goes the DynamicUser route, I’m not sure if it makes sense to require that for every login manager that wants to implement a hypothetical standardized remote greeter protocol.

An alternative, which does follow the model you suggest, might be to have each user who desires remote access configure their desired remote access tool as a persistent user service (with linger enabled for their user). Depending on the tool / configuration, this service could listen for connections directly or register with a system service that would dispatch to it. In either case, it would be the user service that interacts with the login manager to request launching a new headless session for that user when necessary.

That avoids the need to rely on the launched session properly autostarting the user process, and thus avoids the failure mode of waiting fruitlessly for the user process to start when for whatever reason it has failed to do so. For Chrome Remote Desktop, it would also allow multiple users each to set up their own instance using their own Google account, which is something that is possible on Linux today but would not be under the system-service model. The flip side is that only users who had previously configured remote access would be able to log in remotely.

I can understand not wanting to have a login session agent when there isn’t a standardized way to run programs at login screens. (though I still thing you really should have an agent)

I get what you’re saying that GNOME has an advantage here that 3rd party ISVs don’t. If someone drives RFE: monitor system units from user manager · Issue #3312 · systemd/systemd · GitHub forward, that would allow for a more generic answer. It’s not going to help for OpenRC systems though. I’d avoid trying to come up with a least common denominator answer if you can. The linux landscape is large and trying to support more niche user cases could come at the expense of supporting the common cases as well. Your call obviously, just my two cents…

I get the appeal of removing the failure mode entirely, but it should be a detectable failure regardless.
(I suppose you could also just use xdg autostart instead of a systemd --user service, xdg autostart has been around since the very early days and must be widely supported at this point)

Again this is solved by RFE: monitor system units from user manager · Issue #3312 · systemd/systemd · GitHub but there’s clearly a tension between wide compatibility (xdg autostart), and more dynamic behavior (systemd --user)

true.

Note sure what you mean by this, hand-off shouldn’t be hard regardless. Passing file descriptors around isn’t complicated.

sure.

You can have graceful crash handling, termination on disconnection, and process monitoring regardless.

The problem is you’ve got a session running in its own cgroup, with potentially its own selinux staff_u role or whatever, with its own audit session id, and it’s own rlimits. It could theoretically have credentials assigned to it by PAM that are required to get i/o access to its home directory. If you want to run things on behalf of the user, it’s best to make sure you have the same opened credentials as the user and the same limits as the user. You don’t want, e.g., a user to be able gdb attach to this user service and circumvent limits imposed on their account. (ptrace is just one example, you can imagine running as the same uid as the user provides more than one avenue for the user to mess with the process).

Also, in order to impersonate a user, the system service has to run privileged too. That’s not the case otherwise. Obviously it’s better if something getting connected to from the network isn’t running privileged.

In my mind it’s kind of analogous to NAT, you always have the system behind the NAT establish the connections, never have the servers on the other side try to connect to the edge systems.

Anyway, let’s go this route:

  1. You make a decision which way you’re going to go (unprivileged system service/session agent versus privileged system service/session impersonation).
  2. If you do go the impersonation route, for the first cut just throw an autostart file in place that does something like Exec=sh -c 'echo $DBUS_SESSION_BUS_ADDRESS > $XDG_RUNTIME_DIR/session-$XDG_SESSION_ID-bus-address' just to get things up and running.
  3. If you do find sticking with the impersonation route is the way you want to go, we can add a new detail to org.gnome.DisplayManager.RegisterDisplay (alongside session-type and x11-display-name) for the bus address that we call from gdm-{x,wayland}-session, and then we can export it over the display object on the bus.

But let’s not skip straight to 3. Instead make sure this road of dragons is really the way you to go and validate your decision by getting something running first. Once it’s clear that’s the direction you’re headed, we can with change GDM to accommodate.

An alternative, which does follow the model you suggest, might be to have each user who desires remote access configure their desired remote access tool as a persistent user service (with linger enabled for their user).

But if you enable linger for the user, then user services for them will be running when they aren’t even logged in. I thought you were trying to avoid extra processes…

It sounds like you’re onboard with a systemd specific solution, so I really think your best bet is to drive RFE: monitor system units from user manager · Issue #3312 · systemd/systemd · GitHub forward and get something in on that front.

Then you can have the session agent get automatically started by systemd --user when a systemd system service is running and there’s no concern the desktop environment itself will fail to start it, and it won’t run when it’s not supposed to, and you can let systemd --user handle restarting it on crashes etc.

Thanks for the replies.

Would it be reasonable for a future standard API to allow the remote access tool to specify what agent to run when requesting a remote greeter?

IIUC, the idea there is to allow a user service depend on a system service? So one would still have to do, e.g., systemctl --global enable chrome-remote-desktop-user-agent, but the service would only start if the system service were running. Is that correct?

Sure. If it turns out to be untenable to support non-systemd systems or systems without full-featured display managers without a lot of extra work or a degraded experience for everyone, we’re okay accepting those limitations. However, if a standard API can support systems/containers without systemd, and be supported by a dedicated remote login manager on systems without a full-featured display manager running locally, that would be ideal. Certainly, we don’t want to end up in a situation where only GNOME and KDE can reasonably support remote login, and only when paired with their respective preferred display manager.

My concern is that an error like “Timed out while waiting for session agent to start.” is both less immediate and less obvious for how to fix than “Failed to exec session agent: [some specific error message]

I was contemplating a system with multiple configured remote access tools and multiple users. That would result in the user agent for every tool running in every user session. If I’m understanding it correctly, I don’t think the systemd RFE would help, since the system services are running in this case. My thought was that if each user was responsible for enabling the service for the tool they wanted to connect with, there would only be user agents running for the users who actually needed it, and only for the tools they actually use.

This is good information, thanks.

I was imagining using polkit to allow the system service to start the user agent (and nothing else) while running a service user, but there could well be that reason that wouldn’t work that I’m not aware of.

Indeed, we are planning on doing something like that to prototype using the existing GNOME APIs. My discussion here is more to help understand the boundaries of what a standard API might look like, so I can keep that in mind while implementing. Once I have a proof of concept, I’ll hopefully be able to combine the information I’ve gleaned from discussion with experience of implementing the prototype to write up a draft proposal for a standard API.

Would it be reasonable for a future standard API to allow the remote access tool to specify what agent to run when requesting a remote greeter?

Well I personally wouldn’t be thrilled with seeing GDM get in the session management business. It currently starts one process (the session leader) and expects systemd and that leader to do the rest. GDM would be stepping outside of its lane if it provided ways to start processes on behalf of logged in users. Also, you mentioned wanting to have the agent restart automatically on crashes, etc. It really sounds more like the domain of systemd. That’s service management business.

IIUC, the idea there is to allow a user service depend on a system service? So one would still have to do, e.g., systemctl --global enable chrome-remote-desktop-user-agent, but the service would only start if the system service were running. Is that correct?

Well I think the exact design is still up in the air, but I imagine it’d be something like

[Unit]
After=system:google-chrome-desktop

[Install]
WantedBy=graphical-session.target

(not sure exactly what the After line would look like, whatever the scheme ends up being), or maybe a new ConditionSystemUnitRunning=google-chrome-desktop

Something like that.

Certainly, we don’t want to end up in a situation where only GNOME and KDE can reasonably support remote login, and only when paired with their respective preferred display manager.

I get where you’re coming from, as a 3rd party isv, you want to support as much of the linux landscape as you can. I don’t know if you’ll be able to come up with a generic solution that everyone gets on-board with or not.

(fwiw, GNOME currently requires GDM to fully function. If its run from sddm or lightdm or something screen locking and user switching don’t work, and I’m not sure sure those display managers handle xsession and wayland-session files exactly the same way as GDM, too.)

I was contemplating a system with multiple configured remote access tools and multiple users.

Do you expect many systems to have e.g. NiceDCV, chrome-remote-desktop and gnome-remote-desktop system services all installed, enabled, and running? I’d expect in the lions share of cases, one gets selected and enabled. If you really want to optimize for this case, I suppose you could you could ship a .path generator in /run/systemd/user-generators that generates a .path user unit at login that watches /run/chrome-remote-desktop/users/%u and starts chrome-remote-desktop-user-agent when it exists. chrome-remote-desktop could start an agent for a user just by touching /run/gnome/chrome-remote-desktop/users/ejensen or whatever then. That should work today (except for at the GDM login screen until DynamicUser support gets implemented).