GNOME Bugzilla – Bug 693668
RFC: optionally run the greeter session with systemd --user
Last modified: 2018-02-12 15:00:30 UTC
I've been investigating how/whether the gdm greeter (and other special-purpose sessions like gnome-initial-setup) can be made to use systemd --user as their session manager. This allows session services used by the greeter (particularly D-Bus session services) to be started in parallel and managed by the user systemd instance. As a side benefit, it also allows dbus-launch to be avoided entirely. It might even be possible to bypass gnome-session entirely, but for now, gnome-session is just another "child" of the systemd --user process, so it looks something like this: gdm-simple-slave (root) \- systemd --user (gdm) \- dbus-daemon \- gnome-session \- gnome-shell \- gnome-settings-daemon \- pulseaudio \- dconf-service \- etc.
Created attachment 235801 [details] [review] Add a --with-run-dir which sets the default for everything in [/var]/run --- The same as I attached to Bug #692733; I realise it was rejected there. I'll see whether I can work out what's going on with `make distcheck` on that bug...
Created attachment 235802 [details] [review] Get rid of some unused variables --- Cleanup. If it compiles, this can be applied whenever, I think?
Created attachment 235803 [details] [review] GdmLaunchEnvironment: allow a session bus address to be passed in If we're given an explicit session bus address, don't wrap the command in a redundant dbus-launch.
Created attachment 235807 [details] [review] GdmSimpleSlave: give each greeter a unique XDG runtime directory Normally, if a user has multiple login sessions, they're meant to share a runtime directory. For the greeter, we actively don't want that: we want each X11 display to be its own little session, so it can have its own Orca and so on. Create a base directory for them all (which happens to correspond to the default GDM_SCREENSHOT_DIR at the moment) in the main daemon, then create each display's runtime directory in the corresponding launch environment. --- I realise now I attach this that the commit message is wrong, but I don't expect to be able to merge this stuff as-is, so, attaching it for comment anyway. I was briefly using directories like /var/run/gdm/greeter/:0, but have ended up with /var/run/gdm/greeter-:0 instead - I had some trouble with .../greeter getting deleted for some reason. This use of XDG_RUNTIME_DIR contradicts its specification, but I think that might indicate that the specification isn't considering system users: I think we do need the greeter to be able to exist in more than one parallel session, each with its own D-Bus session, even if we don't support more than one parallel D-Bus session for "real users". One possible alternative would be to have some way in which gdm could make the dbus.socket user service (currently in e.g. <https://github.com/sofar/user-session-units>, but it should clearly go upstream to dbus when agreed upon) listen on a socket other than $XDG_RUNTIME_DIR/dbus/user_bus_socket - then we could have multiple D-Bus sessions in one $XDG_RUNTIME_DIR?
Created attachment 235808 [details] [review] Optionally use systemd to start greeter sessions For the moment we assume that each greeter session ID (gdm-shell, and eventually gdm-fallback and gnome-initial-setup) corresponds to a systemd target, e.g. gdm-shell.target. For now we just run one systemd job, gnome-session-gdm-shell.service, which runs the gdm-shell gnome-session session. Later, we could replace that service with the individual bits of gdm-shell. This assumes dbus.service and dbus.socket from user-session-units; they should ideally go upstream, to dbus. --- A production-quality version of this would have to also provide gdm-fallback.target, or perhaps use a common gdm-session.target and pass the preferred session in as an environment variable or something? Having done this, symlinking other services' units into user/gdm-shell.target.wants can be used to preload those services: on my test system I've done this for at-spi-dbus-bus, dconf and pulseaudio (with appropriate systemd <-> D-Bus hookup for at-spi-dbus-bus and dconf).
Created attachment 235809 [details] [review] Work around systemd --user not knowing how to escape D-Bus addresses Workaround for https://bugs.freedesktop.org/show_bug.cgi?id=60499
Review of attachment 235809 [details] [review]: ::: daemon/gdm-simple-slave.c @@ +1035,3 @@ + * This code isn't completely right - in principle the display name + * could contain _ which would lead to aliasing - but it'll do. */ + escaped_display_name = g_uri_escape_string (display_name, "", FALSE); This would be better with Bug #693673 fixed (or we could copy the same function into gdm to do the escaping properly).
(In reply to comment #4) > Normally, if a user has multiple login sessions, they're meant to share > a runtime directory. For the greeter, we actively don't want that: we > want each X11 display to be its own little session, so it can have its > own Orca and so on. This will need discussion with systemd upstream: it clashes with how pam_systemd currently works (creating an XDG_RUNTIME_DIR for each login1.User, which is any overlapping series of login1.Sessions with the same uid) and how upstream want it to operate in future (running a systemd --user and a dbus-daemon --session for each login1.User, whereas here we want one of those per login1.Session). The answer might be an "isolated_session" parameter to pam_systemd, or something, which either suppresses the systemd/dbus-daemon, or makes an XDG_RUNTIME_DIR/systemd/dbus-daemon combination per login1.Session?
See also the thread I started about login sessions vs. user sessions, currently cross-posted to the systemd and gdm lists (let me know if the gdm list should be removed).
(pushing some of the prerequisite patches for now)
Created attachment 237203 [details] [review] proof-of-concept: rely on user@.service for our session buses This requires unmerged patches in systemd. --- This is certainly not suitable for merging - it assumes "the world is systemd" and requires my unmerged patches from systemd bug <https://bugs.freedesktop.org/show_bug.cgi?id=61129>, together with a similar patch for dbus for full functionality - but it does work, in the way that systemd upstream intend (one big session per uid). It will break things that assume one session D-Bus per X11 display - that's unavoidable, given the constraint of the "user bus" design that systemd upstream want. Please contribute to the thread starting at <http://lists.freedesktop.org/archives/systemd-devel/2013-February/009119.html> if you have strong opinions on that. The gnome-session part can be made redundant by making gnome-session prefer to use $XDG_RUNTIME_DIR/dbus/user_bus_socket (if that socket exists) rather than running dbus-launch, or by having pam_systemd put DBUS_SESSION_BUS_ADDRESS in the environment. The greeter part is somewhat harder: at the moment, gdm decides whether to wrap the greeter in dbus-launch based on very incomplete information. One way to fix it would be to move the decision on whether to wrap the greeter in dbus-launch until a later point, after the GdmSessionWorker has run PAM modules. At that point, it can know what the XDG_RUNTIME_DIR is going to be, and also know that if pam_systemd is going to set up dbus/user_bus_socket, then it has already done so; so it can see whether there is a socket, and set DBUS_SESSION_BUS_ADDRESS "at the last moment". Another way to fix it, which I'll try next, would be to not use dbus-launch at all. All the sessions that gdm is willing to execute are gnome-session, which ensures that it has D-Bus - so we can just rely on that, I think?
Created attachment 237210 [details] [review] Don't wrap dbus-launch around gnome-session, only around gdm-simple-chooser gnome-session already knows how to re-exec itself with a gnome-session if necessary, and also (with a patch I've just written) how to pick up the user bus from systemd instead. Don't second-guess that, it just results in extra buses. --- This is an alternative to Attachment #237203 [details]; Attachment #235803 [details] would need to be reverted first. (Sorry, it's taken me a while to piece together how the intended design works...) The "patch I've just written" is Bug #694472.
maybe pam_systemd shoud set DBUS_SESSION_BUS_ADDRESS
*should. What i mean is, if dbus-daemon is going to be socket activated, then setting DBUS_SESSION_BUS_ADDRESS to the socket location should always work, even in the absense of systemd --user right? So we should just unconditionally set it if using systemd. We can set it in gdm based on sd_is_booted() or we can set it in pam_systemd. The latter seems more conceptually clean to me.
(In reply to comment #13) > maybe pam_systemd shoud set DBUS_SESSION_BUS_ADDRESS Yeah, I wondered about that - but that doesn't actually make gdm's life any easier, because we decide whether or not to wrap the process in a dbus-launch long before we do the PAM handshake and find out whether pam_systemd is going to give us a DBUS_SESSION_BUS_ADDRESS (at the moment, it doesn't), or an XDG_RUNTIME_DIR for that matter (it does). > What i mean is, if dbus-daemon is going to be socket activated, then setting > DBUS_SESSION_BUS_ADDRESS to the socket location should always work, even in the > absense of systemd --user right? No, systemd as pid 1 only helps us get a system dbus-daemon socket-activated. We won't get a session dbus-daemon socket-activated unless there is something there to do the activating - namely a 'systemd --user' started on the user's behalf by logind. If you have 1000 users, you don't want pid 1 to listen on 1000 sockets in case each of those users wants a session dbus-daemon :-)
(In reply to comment #15) > We won't get a session dbus-daemon socket-activated unless there is something > there to do the activating - namely a 'systemd --user' started on the user's > behalf by logind. hmm if logind is starting systemd --user, how do we "trigger" it? It can't be just pam_open_session. The greeter does "stuff" after the session is opened before it can be started.
(In reply to comment #16) > hmm if logind is starting systemd --user, how do we "trigger" it? It can't be > just pam_open_session. The greeter does "stuff" after the session is opened > before it can be started. pam_open_session calls login1.Manager.CreateSession, "officially" creating a logind login session. systemd's TODO says logind should start user@`id -u`.service when a uid goes from 0 to 1 login sessions, and stop it when a uid goes from 1 to 0 login sessions. The patches on <https://bugs.freedesktop.org/show_bug.cgi?id=61129> implement that. The assumption made by those patches is that default.target for user sessions starts a `dbus-daemon --session` and maybe some daemons like dconf, but nothing user-visible: GDM remains responsible for starting a gnome-session on the right display. This is all very work-in-progress and I do not recommend actually applying it until the design issues I raised on the systemd mailing list have been solved: in particular, session services that really want to be per-uid (like dconf) are fine in this model, but session services that really want to be per-$DISPLAY (like at-spi-bus-launcher and parts of gnome-settings-daemon) are going to have problems.
basically if pam_systemd's pam_sm_open_session triggers a dbus-daemon getting started, then I think that pam_sm_open_session should putenv the bus address of that dbus daemon it started.