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