{"id":19061940,"url":"https://github.com/chimera-linux/turnstile","last_synced_at":"2025-10-22T06:25:45.421Z","repository":{"id":44726865,"uuid":"437152517","full_name":"chimera-linux/turnstile","owner":"chimera-linux","description":"Independent session/login tracker","archived":false,"fork":false,"pushed_at":"2024-07-28T15:35:30.000Z","size":212,"stargazers_count":70,"open_issues_count":2,"forks_count":6,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-07-29T16:07:19.850Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chimera-linux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-11T00:45:17.000Z","updated_at":"2024-07-29T10:10:27.000Z","dependencies_parsed_at":"2023-11-14T02:39:53.151Z","dependency_job_id":"e3f318f8-b9f9-4010-9280-bb351b1db704","html_url":"https://github.com/chimera-linux/turnstile","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimera-linux%2Fturnstile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimera-linux%2Fturnstile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimera-linux%2Fturnstile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimera-linux%2Fturnstile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chimera-linux","download_url":"https://codeload.github.com/chimera-linux/turnstile/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223770430,"owners_count":17199682,"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":[],"created_at":"2024-11-09T00:23:58.540Z","updated_at":"2025-10-22T06:25:45.361Z","avatar_url":"https://github.com/chimera-linux.png","language":"C++","funding_links":[],"categories":["systemd-logind (Session Manager)"],"sub_categories":[],"readme":"# turnstile\n\nTurnstile is a work in progress effort to create a session/login tracker to\nserve as a fully featured alternative to the logind subproject from systemd,\nand to provide a neutral API to both our session tracker and to logind itself.\n\nIt is:\n\n* a session/login tracker\n* a service-manager-agnostic way to manage per-user service managers\n  for user services\n\nit is not:\n\n* a seat tracker (you want [seatd](https://git.sr.ht/~kennylevinsen/seatd) for\n  that)\n\nit is not yet:\n\n* a library to examine session information\n\n## History\n\nIts original name was dinit-userservd and it was created as a way to auto-spawn\nuser instances of [Dinit](https://github.com/davmac314/dinit) upon login and\nshut them down upon logout, to allow for clean management of user services.\n\nSoon after it outgrew its original responsibilities and gained adjacent\nfunctionality such as handling of `XDG_RUNTIME_DIR`. At that point, it was\ndecided that it would be worthwhile to expand the overall scope, as most of\nthe effort was already there.\n\n## Purpose\n\nIts ultimate goal is to provide a fully featured replacement for the `logind`\ncomponent of systemd, solving the current status quo where `logind` is the\nde-facto standard, but at the same time very much tied to systemd.\n\nWhile there are workarounds such as elogind, these are far from ideal. For\ninstance, elogind is just a stubbed out version of upstream logind, and\nonly provides the bare minimum, so systems using it are left without support\nfor user services and other useful functionality.\n\nThis goal has not yet been accomplished, as at the moment Turnstile is only\na daemon and does not provide any API. This will change in the future. This\nAPI will provide a way to access the session information, but will not deal\nwith seat management. You will be able to use the library together with\n`libseat` without conflicting. The API will expose the bare minimum needed\nfor the two libraries to interoperate.\n\nTurnstile is designed to not care about what service manager it is used with.\nNone of the daemon code cares, instead leaving this to separate backends.\n\n## Backends\n\nTurnstile is capable of supporting multiple service managers, and the code\nmakes no assumptions about what service manager one is using to handle user\ninstances.\n\nThat said, right now the only available backend is for Dinit, which also\nserves as an example for implementation of other backends. There is also\nthe built-in `none` backend, which does not handle user services at all\nand lets the daemon do only session tracking and auxiliary tasks. The\nused backend is configured in `turnstiled.conf`.\n\nA backend is a very trivial shell script. Its responsibility is to launch\nthe service manager and ensure that the daemon is notified of its readiness,\nwhich is handled with a special file descriptor.\n\n## How it works\n\nThere are three parts.\n\n1) The daemon, `turnstiled`.\n2) The PAM module, `pam_turnstile.so`.\n3) The chosen backend.\n\nThe daemon needs to be running in some way. Usually you will spawn it as a\nsystem-wide service. It needs to be running as the superuser. The daemon is\nwhat keeps track of the session state, and what launches the user service\nmanager through the backend.\n\nThe PAM module needs to be in your login path. This will differ per-distro,\nbut typically it will involve a line like this:\n\n```\nsession optional pam_turnstile.so\n```\n\nWhen the daemon starts, it opens a Unix domain socket. This is where it listens\nfor connections. When a user tries to log in, the PAM module will open one such\nconnection and communicate the information to the daemon using a custom internal\nprotocol.\n\nOnce the handshake is done and all the state is properly negotiated, the daemon\nwill try to spawn the service manager for the user. It does so through the\nbackend, which is tasked with the `run` action.\n\nThe backend is a little helper program that can be written in any language, it\ncan e.g. be a shell script. It is started with a clean environment with many\nof the common environment variables, such as `HOME`, `USER`, `LOGNAME`, `SHELL`,\n`PATH` and others, freshly initialized. Typically it is expected to source\nthe system `/etc/profile` for `/bin/sh`. Additionally, it runs within a PAM\nsession (without authentication), which persists for the lifetime of the\nlogin, so PAM environment, resource limits and so on are also set up.\nIt may also be a good idea to put `pam_elogind` or `pam_systemd` in there in\norder to have `logind` recognize the `turnstile` user session as a session\n(which allows it to be tracked by things using it, e.g. `polkitd`).\n\nNote that if you use `pam_systemd` or `pam_elogind` in `turnstiled` PAM\nscript to register it as a session, it will be treated as a session without\na seat. That means things like `polkit` may treat anything running within\n`turnstile` as a non-local session, and may not authenticate the processes.\nThere is no way to get around this limitation outside of patching `polkit`,\nsee Chimera's patches for reference. The alternative is not registering it\nat all, which will not make `polkit` work, as the session tracking logic in\nit will not be able to assign the processes to any UID and things will not\nwork either. Systemd user services are treated specially by `systemd`, as\nthey are recognized by the service manager, but are explicitly not considered\nto be a part of any session (as they are shared); that means `polkit` will\nfall back to looking up whether any seated session for the UID exists.\n\nAfter performing some initial preparation (which is backend-specific), the\nbackend will simply replace itself with the desired service manager. There\nis a special file descriptor that is passed to the backend. The service\nmanager (or possibly even the backend itself) can write a string of data\nin there when it's ready enough to accept outside commands.\n\nOnce that has happened, the daemon will invoke the backend once more, this\ntime with the `ready` action and as a regular (non-login) shell script, without\nany special environment setup. It passes the previously received string as\nan argument. The backend then has the responsibility to wait as long as it\ntakes (or until a timeout is reached) for the initial user services to start\nup.\n\nAfterwards, the daemon will send a message back to the PAM module, allowing\nthe login to proceed. This ensures that by the time the user gets their login\nterminal, the autostarted user services are already up.\n\nWhen the user logs out (or rather, when the last login of the user has logged\nout), this service manager will shut down by default. However, it can also be\nconfigured to linger.\n\n### Auxiliary tasks\n\nThe daemon can also perform various adjacent tasks. As it can be configured\nthrough `turnstiled.conf`, many of these can be enabled or disabled as needed.\n\n#### Rundir management\n\nThe environment variable `XDG_RUNTIME_DIR` is by default set in the user's\nlogin environment. Typically it is something like `/run/user/$UID`.\n\nTurnstile can also create this directory. Whether it creates it by default\ncomes down to how the build is configured. Environments using stock `logind`\nwill want to keep it off in order to avoid conflicting, while others may\nwant to turn it on.\n\nRegardless of the default behavior, it can be altered in the configuration file.\n\n#### Session persistence\n\nIt is possible to configure the sessions to linger, so the user services will\nremain up even after logout. This can be done either per-user, or globally.\n\nNote that session persistence relies on rundir creation being enabled, as in\nthe other case the daemon cannot know whether the other management solution\nis not deleting the rundir, and many user services rely on its existence.\nThis can be manually overridden with an environment variable, at your own\nrisk.\n\n#### D-Bus session bus address\n\nBy default, the address of the D-Bus session bus will be exported into the\nlogin environment and set to something like `unix:path=$XDG_RUNTIME_DIR/bus`,\nif that socket exists and is valid in that path.\n\nThis allows the D-Bus session bus to be managed as a user service, to get\nsystemd-style behavior with a single session bus shared between user logins.\nIt can be explicitly disabled if necessary, but mostly there is no need to\nas the variable will not be exported if the bus does not exist there.\n\nNote that this does not mean the bus address is exported into the activation\nenvironment, as turnstile does not know about it. The user service that spawns\nthe session bus needs to take care of that, e.g. with `dinitctl setenv` for\nDinit. Only this way will other user services know about the session bus.\n\n## Setup\n\nBuild and install the project. It uses [Meson](https://mesonbuild.com/) and\nfollows the standard Meson workflow. Example:\n\n```\n$ mkdir build \u0026\u0026 cd build\n$ meson .. --prefix=/usr\n$ ninja all\n$ sudo ninja install\n```\n\nThe dependencies are:\n\n1) A POSIX-compliant OS (Chimera Linux is the reference platform)\n2) A C++17 compiler\n3) Meson and Ninja (to build)\n5) PAM\n\nThe Dinit backend requires at least Dinit 0.16 or newer, older versions will\nnot work. The project also installs an example Dinit service for starting\nthe daemon.\n\n## Support for other service managers\n\nIf you write a new backend or other functionality related to other service\nmanagers, it would be appreciated if you could submit it upstream (i.e. here).\nThis way we can ensure that other backends stay aligned with the upstream\ndesign goals and will not break over time.\n\nAdditionally, you can get review here, which should ultimately result in\nmore consistent and better quality code. Turnstile is specifically designed\nto help distro interoperability.\n\nSupport for other operating systems (such as the BSDs) is also welcome. While\nthe project tries to be portable, it is being tested solely on Linux. Therefore,\ntesting on other operating systems and potential fixes (please send patches)\nare very helpful. Ultimately I would like the project to serve as a vendor-neutral\ninterface on all Unix-like systems, so that desktop environments and other\nprojects have a quality baseline to target.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchimera-linux%2Fturnstile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchimera-linux%2Fturnstile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchimera-linux%2Fturnstile/lists"}