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