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