]> git.ipfire.org Git - thirdparty/systemd.git/blame - docs/USER_GROUP_API.md
Merge pull request #32324 from mrc0mmand/more-website-fixes
[thirdparty/systemd.git] / docs / USER_GROUP_API.md
CommitLineData
c903ee89
LP
1---
2title: User/Group Record Lookup API via Varlink
5fe63895 3category: Users, Groups and Home Directories
c903ee89 4layout: default
0aff7b75 5SPDX-License-Identifier: LGPL-2.1-or-later
c903ee89
LP
6---
7
8# User/Group Record Lookup API via Varlink
9
0d592a5e
FS
10JSON User/Group Records (as described in the [JSON User Records](/USER_RECORD)
11and [JSON Group Records](/GROUP_RECORD) documents) that are defined on the
8af6cde3 12local system may be queried with a [Varlink](https://varlink.org/) API.
13This API takes both the role of what
e2285c57 14[`getpwnam(3)`](https://man7.org/linux/man-pages/man3/getpwnam.3.html) and
c903ee89
LP
15related calls are for `struct passwd`, as well as the interfaces modules
16implementing the [glibc Name Service Switch
8af6cde3 17(NSS)](https://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html) expose.
18Or in other words, it both allows applications to efficiently query
c903ee89
LP
19user/group records from local services, and allows local subsystems to provide
20user/group records efficiently to local applications.
21
8af6cde3 22The concepts described here define an IPC interface.
23Alternatively, user/group records may be dropped in number of drop-in directories as files where they are
24picked up in addition to the users/groups defined by this IPC logic.
25See
f2147ed5
LP
26[`nss-systemd(8)`](https://www.freedesktop.org/software/systemd/man/nss-systemd.html)
27for details.
28
c903ee89
LP
29This simple API only exposes only three method calls, and requires only a small
30subset of the Varlink functionality.
31
32## Why Varlink?
33
34The API described in this document is based on a simple subset of the
8af6cde3 35mechanisms described by [Varlink](https://varlink.org/).
36The choice of preferring Varlink over D-Bus and other IPCs in this context was made for three reasons:
c903ee89
LP
37
381. User/Group record resolution should work during early boot and late shutdown
8af6cde3 39 without special handling.
40 This is very hard to do with D-Bus, as the broker service for D-Bus generally runs as regular system daemon and is hence only
c903ee89
LP
41 available at the latest boot stage.
42
432. The JSON user/group records are native JSON data, hence picking an IPC
44 system that natively operates with JSON data is natural and clean.
45
463. IPC systems such as D-Bus do not provide flow control and are thus unusable
8af6cde3 47 for streaming data.
48 They are useful to pass around short control messages, but as soon as potentially many and large objects shall be transferred,
c903ee89 49 D-Bus is not suitable, as any such streaming of messages would be considered
8af6cde3 50 flooding in D-Bus' logic, and thus possibly result in termination of communication.
51 Since the APIs defined in this document need to support enumerating potentially large numbers of users and groups,
52 D-Bus is simply not an appropriate option.
c903ee89
LP
53
54## Concepts
55
56Each subsystem that needs to define users and groups on the local system is
57supposed to implement this API, and offer its interfaces on a Varlink
58`AF_UNIX`/`SOCK_STREAM` file system socket bound into the
8af6cde3 59`/run/systemd/userdb/` directory.
60When a client wants to look up a user or group record, it contacts all sockets bound in this directory in parallel,
61and enqueues the same query to each.
62The first positive reply is then returned to the application, or if all fail the last seen error is returned instead.
63(Alternatively a special Varlink service is available,
c903ee89 64`io.systemd.Multiplexer` which acts as frontend and will do the parallel
8af6cde3 65queries on behalf of the client, drastically simplifying client development.
66This service is not available during earliest boot and final shutdown phases.)
c903ee89
LP
67
68Unlike with glibc NSS there's no order or programmatic expression language
8af6cde3 69defined in which queries are issued to the various services.
70Instead, all queries are always enqueued in parallel to all defined services, in order to
c903ee89
LP
71make look-ups efficient, and the simple rule of "first successful lookup wins"
72is unconditionally followed for user and group look-ups (though not for
73membership lookups, see below).
74
75This simple scheme only works safely as long as every service providing
8af6cde3 76user/group records carefully makes sure not to answer with conflicting records.
77This API does not define any mechanisms for dealing with user/group
78name/ID collisions during look-up nor during record registration.
79It assumes the various subsystems that want to offer user and group records to the rest of
c903ee89 80the system have made sufficiently sure in advance that their definitions do not
8af6cde3 81collide with those of other services.
82Clients are not expected to merge multiple definitions for the same user or group,
83and will also not be able to detect conflicts and suppress such conflicting records.
c903ee89
LP
84
85It is recommended to name the sockets in the directory in reverse domain name
86notation, but this is neither required nor enforced.
87
88## Well-Known Services
89
90Any subsystem that wants to provide user/group records can do so, simply by
8af6cde3 91binding a socket in the aforementioned directory.
92By default two services are listening there, that have special relevance:
c903ee89
LP
93
941. `io.systemd.NameServiceSwitch` → This service makes the classic UNIX/glibc
8af6cde3 95 NSS user/group records available as JSON User/Group records.
96 Any such records are automatically converted as needed, and possibly augmented with
c903ee89
LP
97 information from the shadow databases.
98
8af6cde3 992. `io.systemd.Multiplexer` → This service multiplexes client queries to all other running services.
100 It's supposed to simplify client development: in order to look up or enumerate user/group records it's sufficient to talk to
101 one service instead of all of them in parallel.
102 Note that it is not available during earliest boot and final shutdown phases, hence for programs running
103 in that context it is preferable to implement the parallel lookup themselves.
c903ee89
LP
104
105Both these services are implemented by the same daemon
106`systemd-userdbd.service`.
107
8af6cde3 108Note that these services currently implement a subset of Varlink only.
109For example, introspection is not available, and the resolver logic is not used.
c903ee89
LP
110
111## Other Services
112
4c2cf157 113The `systemd` project provides three other services implementing this
c903ee89
LP
114interface. Specifically:
115
1161. `io.systemd.DynamicUser` → This service is implemented by the service
117 manager itself, and provides records for the users and groups synthesized
118 via `DynamicUser=` in unit files.
119
1202. `io.systemd.Home` → This service is implemented by `systemd-homed.service`
121 and provides records for the users and groups defined by the home
122 directories it manages.
123
4c2cf157
LP
1243. `io.systemd.Machine` → This service is implemented by
125 `systemd-machined.service` and provides records for the users and groups used
126 by local containers that use user namespacing.
127
8af6cde3 128Other projects are invited to implement these services too.
129For example, it would make sense for LDAP/ActiveDirectory projects to implement these
c903ee89
LP
130interfaces, which would provide them a way to do per-user resource management
131enforced by systemd and defined directly in LDAP directories.
132
133## Compatibility with NSS
134
8af6cde3 135Two-way compatibility with classic UNIX/glibc NSS user/group records is provided.
136When using the Varlink API, lookups into databases provided only via
137NSS (and not natively via Varlink) are handled by the `io.systemd.NameServiceSwitch` service (see above).
138When using the NSS API (i.e. `getpwnam()` and friends) the `nss-systemd` module will automatically
139synthesize NSS records for users/groups natively defined via a Varlink API.
140Special care is taken to avoid recursion between these two compatibility mechanisms.
c903ee89
LP
141
142Subsystems that shall provide user/group records to the system may choose
143between offering them via an NSS module or via a this Varlink API, either way
8af6cde3 144all records are accessible via both APIs, due to the bidirectional forwarding.
145It is also possible to provide the same records via both APIs
146directly, but in that case the compatibility logic must be turned off.
147There are mechanisms in place for this, please contact the systemd project for
c903ee89
LP
148details, as these are currently not documented.
149
150## Caching of User Records
151
8af6cde3 152This API defines no concepts for caching records.
153If caching is desired it should be implemented in the subsystems that provide the user records,
154not in the clients consuming them.
c903ee89
LP
155
156## Method Calls
157
158```
159interface io.systemd.UserDatabase
160
161method GetUserRecord(
162 uid : ?int,
163 userName : ?string,
164 service : string
165) -> (
166 record : object,
fa0e23c9 167 incomplete : bool
c903ee89
LP
168)
169
170method GetGroupRecord(
171 gid : ?int,
172 groupName : ?string,
173 service : string
174) -> (
175 record : object,
fa0e23c9 176 incomplete : bool
c903ee89
LP
177)
178
179method GetMemberships(
180 userName : ?string,
181 groupName : ?string,
182 service : string
183) -> (
184 userName : string,
185 groupName : string
186)
187
188error NoRecordFound()
189error BadService()
190error ServiceNotAvailable()
191error ConflictingRecordFound()
56870d32 192error EnumerationNotSupported()
c903ee89
LP
193```
194
8af6cde3 195The `GetUserRecord` method looks up or enumerates a user record.
196If the `uid` parameter is set it specifies the numeric UNIX UID to search for.
197If the `userName` parameter is set it specifies the name of the user to search for.
198Typically, only one of the two parameters are set, depending whether a
199look-up by UID or by name is desired.
200However, clients may also specify both parameters, in which case a record matching both will be returned, and if only
201one exists that matches one of the two parameters but not the other an error of `ConflictingRecordFound` is returned.
202If neither of the two parameters are set the whole user database is enumerated.
203In this case the method call needs to be made with `more` set, so that multiple method call replies may be generated as
c903ee89
LP
204effect, each carrying one user record.
205
206The `service` parameter is mandatory and should be set to the service name
207being talked to (i.e. to the same name as the `AF_UNIX` socket path, with the
208`/run/systemd/userdb/` prefix removed). This is useful to allow implementation
209of multiple services on the same socket (which is used by
210`systemd-userdbd.service`).
211
212The method call returns one or more user records, depending which type of query is
8af6cde3 213used (see above). The record is returned in the `record` field.
214The `incomplete` field indicates whether the record is complete.
215Services providing user record lookup should only pass the `privileged` section of user records to
c903ee89 216clients that either match the user the record is about or to sufficiently
8af6cde3 217privileged clients, for all others the section must be removed so that no sensitive data is leaked this way.
218The `incomplete` parameter should indicate whether the record has been modified like this or not (i.e. it is `true` if a
c903ee89
LP
219`privileged` section existed in the user record and was removed, and `false` if
220no `privileged` section existed or one existed but hasn't been removed).
221
222If no user record matching the specified UID or name is known the error
223`NoRecordFound` is returned (this is also returned if neither UID nor name are
224specified, and hence enumeration requested but the subsystem currently has no
225users defined).
226
227If a method call with an incorrectly set `service` field is received
8af6cde3 228(i.e. either not set at all, or not to the service's own name) a `BadService` error is generated.
229Finally, `ServiceNotAvailable` should be returned when the backing subsystem is not operational for some reason and hence no information
230about existence or non-existence of a record can be returned nor any user record at all.
231(The `service` field is defined in order to allow implementation of daemons that provide multiple distinct user/group services over the same
c903ee89 232`AF_UNIX` socket: in order to correctly determine which service a client wants
f223fd6a 233to talk to, the client needs to provide the name in each request.)
c903ee89
LP
234
235The `GetGroupRecord` method call works analogously but for groups.
236
8af6cde3 237The `GetMemberships` method call may be used to inquire about group memberships.
238The `userName` and `groupName` arguments take what the name suggests.
239If one of the two is specified all matching memberships are returned,
240if neither is specified all known memberships of any user and any group are returned.
241The return value is a pair of user name and group name, where the user is a member of the group.
242If both arguments are specified the specified membership will be tested for, but no others, and the pair is returned if it is
c903ee89
LP
243defined. Unless both arguments are specified the method call needs to be made
244with `more` set, so that multiple replies can be returned (since typically
8af6cde3 245there are multiple members per group and also multiple groups a user is member of).
246As with `GetUserRecord` and `GetGroupRecord` the `service`
c903ee89 247parameter needs to contain the name of the service being talked to, in order to
8af6cde3 248allow implementation of multiple services within the same IPC socket.
249In case no matching membership is known `NoRecordFound` is returned.
250The other two errors are also generated in the same cases as for `GetUserRecord` and
c903ee89
LP
251`GetGroupRecord`.
252
253Unlike with `GetUserRecord` and `GetGroupRecord` the lists of memberships
8af6cde3 254returned by services are always combined.
255Thus unlike the other two calls a membership lookup query has to wait for the last simultaneous query to complete
c903ee89
LP
256before the complete list is acquired.
257
8af6cde3 258Note that only the `GetMemberships` call is authoritative about memberships of users in groups.
259i.e. it should not be considered sufficient to check the
c903ee89 260`memberOf` field of user records and the `members` field of group records to
8af6cde3 261acquire the full list of memberships.
262The full list can only be determined by `GetMemberships`, and as mentioned requires merging of these lists of all local services.
263Result of this is that it can be one service that defines a user A,
264and another service that defines a group B, and a third service that declares that A is a member of B.
c903ee89 265
56870d32 266Looking up explicit users/groups by their name or UID/GID, or querying
8af6cde3 267user/group memberships must be supported by all services implementing these interfaces.
268However, supporting enumeration (i.e. user/group lookups that may
269result in more than one reply, because neither UID/GID nor name is specified) is optional.
270Services which are asked for enumeration may return the `EnumerationNotSupported` error in this case.
56870d32 271
c903ee89 272And that's really all there is to it.