{"id":22286858,"url":"https://github.com/killingspark/howlogindworks","last_synced_at":"2026-01-06T03:53:11.015Z","repository":{"id":52805866,"uuid":"263976623","full_name":"KillingSpark/HowLogindWorks","owner":"KillingSpark","description":"A collection of info about session management with logind","archived":false,"fork":false,"pushed_at":"2023-08-08T10:02:06.000Z","size":23,"stargazers_count":33,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-30T18:20:50.529Z","etag":null,"topics":["documentation","logind","systemd"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KillingSpark.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-14T17:08:11.000Z","updated_at":"2024-12-12T00:38:18.000Z","dependencies_parsed_at":"2022-08-23T07:40:47.824Z","dependency_job_id":null,"html_url":"https://github.com/KillingSpark/HowLogindWorks","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KillingSpark%2FHowLogindWorks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KillingSpark%2FHowLogindWorks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KillingSpark%2FHowLogindWorks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KillingSpark%2FHowLogindWorks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KillingSpark","download_url":"https://codeload.github.com/KillingSpark/HowLogindWorks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245542661,"owners_count":20632537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["documentation","logind","systemd"],"created_at":"2024-12-03T16:58:22.841Z","updated_at":"2026-01-06T03:53:10.988Z","avatar_url":"https://github.com/KillingSpark.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# How does Logind work\nThis document tries to collect all info I can gather about the workings and magic of session management, as performed by logind.\nSince logind is the predominant session manager this is kinda the 'current state of the art\".\n\nNote that I did not read any source-code. So everything here could be wrong, if the available documentation disagrees with the code.\nI had three ways of figuring stuff out:\n1. Reading blogs\n1. Reading man pages\n1. Poking my own system and looking for clues\n\nIf I got anything wrong and you have better facts, please file and issue! I would gladly accept PRs or suggestions,\nif you want to improve the text (I am sadly not a really good writer).\n\nI might sound a bit negative in parts of the following text. I would like to emphasize that logind has introduced a lot of cool features\nthat make the linux desktop multi-user experience better. Understanding how stuff works is the first step on making stuff even better and I hope\nthis can make the journey of understanding logind easier for others.\n\n## Big picture\nSo, session management needs to work on a number of different things to be useful.\nLets first try to formulate the goal logind tries to achieve with session management, to get some overview over what we are dealing with.\nAfter that we can get into the details.\n\n* A `User` should be able to login on a `Loginmanager`. This should put the `User` into a newly created `Session`.\n* The login could happen on a set of hardware (as opposed to logging in over ssh or something similar). Lets call this set of hardware a `Seat`.\n* This `Seat` should be accessible to this session and not be available to other sessions until this session releases the `Seat`.\n* The `SessionManager` needs to keep track of the sessions and their assigned seats. It also watches for exited sessions and reclaims their `Seat`s.\n* The `SessionManager` can remove a session from a seat and give access to another session if needed.\n\nNow we have a whole bunch of concepts session management needs to deal with. All of this has of course many details that need to be talked about.\nThis is what the next sections will be about.\n\n## Lets get detailed!\nIn the following sections I will describe in a lot of detail how the stuff in the \"big picture\" section work. I tried to make them as separate as possible,\nsome forward/back references were unavoidable though. I hope this is still readable to anyone that is not me.\n\n### Users\nUsers and their identification and authentification are luckily out of the scope of session management. We expect this to be handled by something else. Logind\nexpects PAM to be used, and most linux distros include PAM, so probably some PAM module will be used to authenticate a user when he logs in. This is (as far as I know) not required\nthough and I am not sure if Logind actually cares what kind of login/authentication mechanism is used, as long as it behaves similarly to the systemd_pam module.\n\n\n### Seats\nReasoning about which hardware belongs to which seat is hard. That's why logind does not do it. This is part of udev. I still want to talk about it because there\nis a weird interaction between user ACLs set by logind and udev.\n\nOk so short intro for udev: linux exposes a very messy and complicated device file tree in `/sys/devices`, and we don't want to deal with that directly.\nUdev looks at it and makes some sense out of it and provides a simpler\nabstraction. It also has a collection of device-ids, vendor-ids, etc... that help it classify these devices. It then creates device files in /dev for you to\ninteract with the devices (or device drivers). It also listens to events that indicate new/removed devices and takes appropriate actions.\n\nHere is a TL;DR for the following:\n1. Udev tags devices with seat information, based on rules (see man udev for more info on the rules, it's basically a fancy matching engine)\n1. If a device only has a 'seat' tag but no info about which seat it belongs to, it belongs to seat0\n1. Children of devices that are tagged 'seat' are inherit the 'seat' tag implicitly... (WHY!)\n1. Udev tags some devices with 'uaccess' which means the sessions user should have direct access to that device. This seems to only be applied to some output devices lie sound.\n1. Devices tagged with 'uaccess' seem to be a subset of devices tagged 'seat', or are children of devices tagged 'seat' \n1. The effects of uaccess are applied by udev itself, not logind\n\nUdev tags devices with useful info. The tags that interest logind are the seat related ones. Udev tags some devices with `seat` if they belong to a seat.\nWhich seat is stated in another property of this device. Note that not all sub-devices of a device are tagged with `seat`. This still means that they belong to the\nsame seat as their tagged parent. There is also the `seat-master` tag that makes a seat exist (in most cases a monitor / graphics card).\n\nThere is another relevant tag: `uaccess`. When trying to find out what that tag means I stumbled upon this gem of an issue on the systemd repo: [Document the uaccess mechanism / dynamic device permissions](https://github.com/systemd/systemd/issues/4288) which is open since 2016. Documenting stuff is hard.\n\nAfter searching the net for the doc that systemd doesn't provide I found [this link from 2012](https://enotty.pipebreaker.pl/2012/05/23/linux-automatic-user-acl-management/). It shows how udev at that time ran a command `/usr/lib/systemd/systemd-uaccess $env{DEVNAME} $env{ID_SEAT}` for each device\nwith the tag `uaccess`. This utility does not exist anymore (at least not on my arch installation) but I am guessing that something similar is still happening.\nWhat that command apparently did is creating the appropriate ACLs based on which seat the device was assigned to.\n\nThis means logind is not the only entity granting users access to devices but udev might do that too, when a new device gets plugged in. I hope that is not causing any\nraces when switching sessions and plugging in devices...\n\nSo all devices that are tagged `uaccess` are tagged `seat` but not all `seat` are `uaccess`.\nFrom what I gathered from poking around in the output of `udevadm info -e` sound output devices and video cards are the only devices marked `uaccess`.\nIt makes sense that not everyone can open input devices like keyboards (else keylogging would be easy). See in the sections\nbelow, how access to these devices is realized with logind as a proxy. Or you can have a look at [this page](https://dvdhrm.wordpress.com/2013/08/25/sane-session-switching/), which explains this too and has some cool pictures\n\nHow exactly multi-seat is done in udev-rules is not clear to me. I think an admin has to manually make rules to say which device belongs to which seat. Otherwise\nall devices belong to the default seat `seat0`.\n\n### Create a session on login\nHaving Users and Seat management out of the way, we can start worrying about the stuff we really want to do: create and manage sessions!\nSo what happens when a `DisplayManager` like SDDM wants to start a session for a newly logged in user?\n\nThe goal is simple: notify the session manager that a new session exists. Logind uses a\ndedicated PAM module that notifies logind about the new session.\n(\"Creating/closing sessions is exclusively the job of PAM and its pam_systemd module\" [\\[1\\]](https://www.freedesktop.org/wiki/Software/systemd/logind/)).\n\nThe PAM modules are executed by the `LoginManager` or `DisplayManager`, which can have funny side effects, see below.\n\nThe CreateSession call [\\[1\\]](https://www.freedesktop.org/wiki/Software/systemd/logind/) on the dbus API of logind gives a good overview of\n1. What is needed to create a new session\n2. How messy systemd APIs are\n\nThere will be a lot of guessing, and me saying I don't know what is happening. I promise the later parts of this document will be better informed.\nThere are more and better sources on other parts of loginds inner workings. If anyone can shed light on what some of the more mysterious\nparameters do please let me know!\n\n```\nCreateSession(in  u uid,\n    in  u pid,\n    in  s service,\n    in  s type,\n    in  s class,\n    in  s desktop,\n    in  s seat_id,\n    in  u vtnr,\n    in  s tty,\n    in  s display,\n    in  b remote,\n    in  s remote_user,\n    in  s remote_host,\n    in  a(sv) properties,\n    out s session_id,\n    out o object_path,\n    out s runtime_path,\n    out h fifo_fd,\n    out u uid,\n    out s seat_id,\n    out u vtnr,\n    out b existing);\n```\n\n#### CreateSession in detail\n\nSo, lets pick that apart. Creating a session needs info about which user that session is being created for, identified by a `uid`. The `pid` is probably\nthe `root` or `parent` process for this new session. So far this is relatively straight forward.\n\nNow it gets weirder, why is a session associated with a service?\nAccording to [\\[1\\]](https://www.freedesktop.org/wiki/Software/systemd/logind/) this is \"Service encodes the PAM service name that registered the session\". I am not entirely sure why this is necessary info to the session manager, but it is not entirely weird. Maybe a session created by some PAM module need special handling.\n\n\"Type encodes the session type. It's one of \"unspecified\" (for cron PAM sessions and suchlike), \"tty\" (for text logins) or \"x11\"/\"mir\"/\"wayland\" (for graphical logins)\".\nI don't really get why this is important, a session might switch between text and graphical mode without involving the session manager so that should not really matter.\n\n\"Class encodes the session class. It's one of \"user\" (for normal user sessions), \"greeter\" (for display manager pseudo-sessions), \"lock-screen\" (for display lock screens)\".\nHow are sessions created that are not user? I thought only systemd_pam calls CreateSession. But the greeter and lockscreen probably do not go through a PAM login session, do they?\n\nThe `desktop` parameter is entirely undescribed. I guess it was intended to tell logind which DE a user is using and was not needed in the end?\n\nOk so the `seat_id` makes sense. A session needs to be placed in a seat. This does mean that the systemd_pam is able to figure out on which seat the current process is\nrunning (or somehow else infer on which seat it should be placed).\n\nThe `vtnr` is necessary for the good old session switching with alt+ctrl+fx (\"VTNr encodes the virtual terminal number of the session\").\nThere might be more than one session on `seat_id` but only one active one. I always thought that ttyX is always associated with the virtual terminal with\nnumber X but I might be wrong, so the `tty` parameter encodes that.\n\n`remote`, `remote_user`, and `remote_host` confuse me a little. I thought `remote` would be inferable from `service`. Maybe not. Why logind is interested in\nthe `remote_user` and `remote_host` and how it gets these values is unclear to me.\n\n`properties` is another opaque parameter, probably used to make extensions to the API without actually changing the API. I don't know what this might contain.\n\nThe output is relatively straight forward. I am guessing that the `uid`, `seat_id`, and `vtnr` are only relevant if `existing` is true. How a session would be created a\nsecond time is unclear to me, it seems like that should rather be an error, but that's a design choice.\n\nThe `fifo_fd` is used to detect when the process owning the PAM session exits.\nlogind passes one end of a FIFO to the pam_systemd plugin which doesn't really do anything with it, the pipe is just open for the lifetime of the process that invoked the plugin.\nWhen logind gets a notification that the pipe is closed, it knows that the session is definitely over, even if the process just died suddenly.\n\n#### Effects of creating a session\nCreating a session with logind has a number of important effects.\n\n1. Systemd creates a new scope in the slice of the user specified by `uid`\n1. Systemd moves the `pid` into that scope.\n    * I am pretty sure that the systemd_pam module reports its own PID\n    * This means the process that ran the PAM modules is now in a fresh otherwise empty cgroup, that has nothing to do anymore with the cgroup the `LoginManager`\n        was in originally.\n    * This means if you do not fork+exec before you execute the PAM modules your `LoginManager` is suddenly the session root. This could prove to be problematic\n        for detecting exited sessions. I hope logind checks that no pid is a root for multiple sessions, but I did not check that.\n    * This is not properly documented in [\\[2\\]](https://www.freedesktop.org/wiki/Software/systemd/writing-display-managers/). This is mostly concerned with porting\n        from ConsoleKit, maybe it was required to have fork+exec there too.\n1. It sets ACLs to some device files, but not all. Which devices and how this is determined will be described in a later section.\n    Anyways you can now in some way or another get access to all the devices on the seat you logged into.\n\nGreat! Now we have created a session and have been seated (haha get it...) by logind. Our `LoginManager` may now start the actual session and drop us into KDE or Gnome\nor i3 or whatever it was we originally wanted to start before being sidetracked by the session shenanigans.\n\n### Accessing devices with logind\nX11 and wayland need to access devices. To mouse/keyboard/touch/... for input and to screens for output. Traditionally the X11 server needed to get access to them\nby being root and then drop privileges. This is obviously a bad choice since we are starting a session for a user. And that user better not get root access!\n\nIn comes logind providing the possibility to start the session completely as the dedicated user and not rely on that process to properly drop privileges.\nThis is possible by logind playing device-broker. There is a nice article with good graphics here: [\\[3\\]](https://dvdhrm.wordpress.com/2013/08/25/sane-session-switching/).\n\nThe summary is:\n1. One process needs to call `TakeControl(...)` on the dbus interface of the created session\n1. This process can call `TakeDevice(...)` which returns a filedescriptor\n1. This filedescriptor can be revoked, if this happens the process can call `TakeDevice(...)` again to try to regain access\n\nLogind can open these devices and only logind needs to run with elevated privileges. Everything else needs to go through logind to get access to devices (at least for input. There are some exceptions, where devices are accessible to normal users.)\n\n#### Libinput\nX11 and Wayland compositors do not themselves deal with device files. Both rely on abstractions.\nX11 has multiple input drivers (a libinput based one exists and is widely used), while wayland compositors seem to solely rely on libinput.\nFor this to work libinput needs to get access to the device files. But libinput does not depend on logind. So how does that work?\n\nLibinput doesn't care about sessions and whatnot, it just cares about getting device-input from the kernel to the user of the library. It does\nprovide a convenient notion of `seats` from udev which allows the user to get events from the whole seat instead of handling all devices separately.\n\nIt makes the user open a device themselves, side-stepping the whole permission problems and handing them to the user of the library. The user needs\nto provide a function called `open_restricted` which returns a filedescriptor for a given device path. This way we can integrate logind support without\nlibinput directly depending on logind.\n\nSee [here](https://wayland.freedesktop.org/libinput/doc/latest/api/structlibinput__interface.html#ae445aaa330e4eb7df6650fbc6428022a) for the doc\nfor `open_restricted`.\n\nAs an example of how this can be used see these two files from wlroots, a popular wayland compositor library\n* https://github.com/swaywm/wlroots/blob/master/backend/libinput/backend.c\n    * setup of libinput and uses the sessions routines to open the device files\n* https://github.com/swaywm/wlroots/blob/master/backend/session/logind.c\n    * uses the logind dbus call `TakeDevice(...)` to open devices and return the filedescriptors\n\n### Switching Sessions / Removing a Session from a Seat\nOk, so far we were able to log into the system, create a session and be able to use out mouse, keyboard and display to look at funny cat videos on\nyoutube [example](https://www.youtube.com/watch?v=dQw4w9WgXcQ).\nThis is fine and dandy, but our boss is already coming dangerously close to realizing we are not working as much as we should, so we want to prepare a session\nwith $SERIOUS_USER and be able to switch to that quickly if he comes around to check in with us.\n\nSo, we all know how this works, press alt+ctrl+F1 and login again as $SERIOUS_USER, start some busy looking screens and go back to the session with the cat videos.\n\nNow it gets tricky. Remember how we said only one session should have access to a seat at a given time? How is this enforced? We can't rely on\nevery session being nice and cooperative and bug-free.\nThe filedescriptors for the devices are open, logind gave them to the session. And we cannot close the filedescriptors in other processes. Or can we?\n\nNot exactly. But the kernel provides us with something similar for filedescriptors associated with evdev devices: an ioctl command `EVIOCREVOKE`.\nThis basically closes the filedescriptor but not completely. It stays valid in all processes that still also have it but all reads after this ioctl() will not return\nany events but will indicate that access has been revoked.\n\nSo now logind can remove a session from a seat and enforce that this session can no longer read any input events, since (hopefully) all\ninput device filedescriptors have been handed to the session through logind. When the removed session gets reactivated it has to regain access by asking logind for\nnew, fresh filedescriptors.\n\n### Watching for exiting sessions\nThis is a nontrivial part of session management. You need to somehow be able to tell which processes belong to which session be able to receive\nnotifications when they exit. This could probably be done by using the posix sessionids in most cases. \n\nBut those are not reliable since processes can leave their session and make a new one. Now we don't know anymore what is going on!\nThis seems counter-intuitive at first, but it actually makes sense when thinking about (maybe the main) usecase for posix sessions: shells!\nYou want your shell to be it's own session, so it can have control over all it's spawned children and switch fore-/background tasks. But you also want\nyou shell to be able to spawn new shells (e.g. if you run tmux to spawn multiple sessions).\n\nCgroups are a bit different in this regard. They are not meant to be manipulated by the processes themselves. Processes should not care about cgroups at all,\nsince they most likely cant do anything to change the restrictions that they place on them, and if the permissions on the pseudo-filesystem are managed the right way,\ncgroups provide a reliable way to track which process was started in which group of processes, e.g. a session. \n\nThat is why logind pushes the first process into a cgroup right at creation of a session. With cgroups we can reliably track which process\nbelongs to which session, and we also can easily use inotify to get the needed notifications. Cgroups are nice!\n(as long as no root user fiddles around with those cgroups\n[WHICH ARE SYSTEMD PROPERTY AND IF YOU DARE TOUCH THEM YOU ARE A BAD PERSON](https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/)).\n\nWhat systemd does is not really magical though. Sessions belong to users, and systemd has a concept to track processes not actually started by systemd itself: scopes.\nSo it opens a scope in the slice of that user using this naming scheme:\n```\n/sys/fs/cgroup/unified/user.slice/user-{{UID}}.slice/session-{{SessionID}}.scope\n```\nFor example, the session I am currently writing this from is:\n```\n/sys/fs/cgroup/unified/user.slice/user-1000.slice/session-2.scope\n```\n\n# Sources\nThese are the main sources. Scattered over the text there are some more links. Man pages were a source of information too.\n\n* \\[1\\] https://www.freedesktop.org/wiki/Software/systemd/logind/\n* \\[2\\] https://www.freedesktop.org/wiki/Software/systemd/writing-display-managers/\n* \\[3\\] https://dvdhrm.wordpress.com/2013/08/25/sane-session-switching/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkillingspark%2Fhowlogindworks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkillingspark%2Fhowlogindworks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkillingspark%2Fhowlogindworks/lists"}