docs/USER_GROUP_API: format text

This commit is contained in:
hulkoba 2024-02-26 14:38:49 +01:00
parent 9ed6cf02b2
commit 8af6cde31d
No known key found for this signature in database
GPG key ID: ACB6C4A3A4F2BE2F

View file

@ -9,19 +9,20 @@ SPDX-License-Identifier: LGPL-2.1-or-later
JSON User/Group Records (as described in the [JSON User Records](USER_RECORD) JSON User/Group Records (as described in the [JSON User Records](USER_RECORD)
and [JSON Group Records](GROUP_RECORD) documents) that are defined on the and [JSON Group Records](GROUP_RECORD) documents) that are defined on the
local system may be queried with a [Varlink](https://varlink.org/) API. This local system may be queried with a [Varlink](https://varlink.org/) API.
API takes both the role of what This API takes both the role of what
[`getpwnam(3)`](https://man7.org/linux/man-pages/man3/getpwnam.3.html) and [`getpwnam(3)`](https://man7.org/linux/man-pages/man3/getpwnam.3.html) and
related calls are for `struct passwd`, as well as the interfaces modules related calls are for `struct passwd`, as well as the interfaces modules
implementing the [glibc Name Service Switch implementing the [glibc Name Service Switch
(NSS)](https://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html) (NSS)](https://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html) expose.
expose. Or in other words, it both allows applications to efficiently query Or in other words, it both allows applications to efficiently query
user/group records from local services, and allows local subsystems to provide user/group records from local services, and allows local subsystems to provide
user/group records efficiently to local applications. user/group records efficiently to local applications.
The concepts described here define an IPC interface. Alternatively, user/group The concepts described here define an IPC interface.
records may be dropped in number of drop-in directories as files where they are Alternatively, user/group records may be dropped in number of drop-in directories as files where they are
picked up in addition to the users/groups defined by this IPC logic. See picked up in addition to the users/groups defined by this IPC logic.
See
[`nss-systemd(8)`](https://www.freedesktop.org/software/systemd/man/nss-systemd.html) [`nss-systemd(8)`](https://www.freedesktop.org/software/systemd/man/nss-systemd.html)
for details. for details.
@ -31,58 +32,55 @@ subset of the Varlink functionality.
## Why Varlink? ## Why Varlink?
The API described in this document is based on a simple subset of the The API described in this document is based on a simple subset of the
mechanisms described by [Varlink](https://varlink.org/). The choice of mechanisms described by [Varlink](https://varlink.org/).
preferring Varlink over D-Bus and other IPCs in this context was made for three The choice of preferring Varlink over D-Bus and other IPCs in this context was made for three reasons:
reasons:
1. User/Group record resolution should work during early boot and late shutdown 1. User/Group record resolution should work during early boot and late shutdown
without special handling. This is very hard to do with D-Bus, as the broker without special handling.
service for D-Bus generally runs as regular system daemon and is hence only 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
available at the latest boot stage. available at the latest boot stage.
2. The JSON user/group records are native JSON data, hence picking an IPC 2. The JSON user/group records are native JSON data, hence picking an IPC
system that natively operates with JSON data is natural and clean. system that natively operates with JSON data is natural and clean.
3. IPC systems such as D-Bus do not provide flow control and are thus unusable 3. IPC systems such as D-Bus do not provide flow control and are thus unusable
for streaming data. They are useful to pass around short control messages, for streaming data.
but as soon as potentially many and large objects shall be transferred, They are useful to pass around short control messages, but as soon as potentially many and large objects shall be transferred,
D-Bus is not suitable, as any such streaming of messages would be considered D-Bus is not suitable, as any such streaming of messages would be considered
flooding in D-Bus' logic, and thus possibly result in termination of flooding in D-Bus' logic, and thus possibly result in termination of communication.
communication. Since the APIs defined in this document need to support Since the APIs defined in this document need to support enumerating potentially large numbers of users and groups,
enumerating potentially large numbers of users and groups, D-Bus is simply D-Bus is simply not an appropriate option.
not an appropriate option.
## Concepts ## Concepts
Each subsystem that needs to define users and groups on the local system is Each subsystem that needs to define users and groups on the local system is
supposed to implement this API, and offer its interfaces on a Varlink supposed to implement this API, and offer its interfaces on a Varlink
`AF_UNIX`/`SOCK_STREAM` file system socket bound into the `AF_UNIX`/`SOCK_STREAM` file system socket bound into the
`/run/systemd/userdb/` directory. When a client wants to look up a user or `/run/systemd/userdb/` directory.
group record, it contacts all sockets bound in this directory in parallel, and When a client wants to look up a user or group record, it contacts all sockets bound in this directory in parallel,
enqueues the same query to each. The first positive reply is then returned to and enqueues the same query to each.
the application, or if all fail the last seen error is returned The first positive reply is then returned to the application, or if all fail the last seen error is returned instead.
instead. (Alternatively a special Varlink service is available, (Alternatively a special Varlink service is available,
`io.systemd.Multiplexer` which acts as frontend and will do the parallel `io.systemd.Multiplexer` which acts as frontend and will do the parallel
queries on behalf of the client, drastically simplifying client queries on behalf of the client, drastically simplifying client development.
development. This service is not available during earliest boot and final This service is not available during earliest boot and final shutdown phases.)
shutdown phases.)
Unlike with glibc NSS there's no order or programmatic expression language Unlike with glibc NSS there's no order or programmatic expression language
defined in which queries are issued to the various services. Instead, all defined in which queries are issued to the various services.
queries are always enqueued in parallel to all defined services, in order to Instead, all queries are always enqueued in parallel to all defined services, in order to
make look-ups efficient, and the simple rule of "first successful lookup wins" make look-ups efficient, and the simple rule of "first successful lookup wins"
is unconditionally followed for user and group look-ups (though not for is unconditionally followed for user and group look-ups (though not for
membership lookups, see below). membership lookups, see below).
This simple scheme only works safely as long as every service providing This simple scheme only works safely as long as every service providing
user/group records carefully makes sure not to answer with conflicting user/group records carefully makes sure not to answer with conflicting records.
records. This API does not define any mechanisms for dealing with user/group This API does not define any mechanisms for dealing with user/group
name/ID collisions during look-up nor during record registration. It assumes name/ID collisions during look-up nor during record registration.
the various subsystems that want to offer user and group records to the rest of It assumes the various subsystems that want to offer user and group records to the rest of
the system have made sufficiently sure in advance that their definitions do not the system have made sufficiently sure in advance that their definitions do not
collide with those of other services. Clients are not expected to merge collide with those of other services.
multiple definitions for the same user or group, and will also not be able to Clients are not expected to merge multiple definitions for the same user or group,
detect conflicts and suppress such conflicting records. and will also not be able to detect conflicts and suppress such conflicting records.
It is recommended to name the sockets in the directory in reverse domain name It is recommended to name the sockets in the directory in reverse domain name
notation, but this is neither required nor enforced. notation, but this is neither required nor enforced.
@ -90,27 +88,25 @@ notation, but this is neither required nor enforced.
## Well-Known Services ## Well-Known Services
Any subsystem that wants to provide user/group records can do so, simply by Any subsystem that wants to provide user/group records can do so, simply by
binding a socket in the aforementioned directory. By default two binding a socket in the aforementioned directory.
services are listening there, that have special relevance: By default two services are listening there, that have special relevance:
1. `io.systemd.NameServiceSwitch` → This service makes the classic UNIX/glibc 1. `io.systemd.NameServiceSwitch` → This service makes the classic UNIX/glibc
NSS user/group records available as JSON User/Group records. Any such NSS user/group records available as JSON User/Group records.
records are automatically converted as needed, and possibly augmented with Any such records are automatically converted as needed, and possibly augmented with
information from the shadow databases. information from the shadow databases.
2. `io.systemd.Multiplexer` → This service multiplexes client queries to all 2. `io.systemd.Multiplexer` → This service multiplexes client queries to all other running services.
other running services. It's supposed to simplify client development: in It's supposed to simplify client development: in order to look up or enumerate user/group records it's sufficient to talk to
order to look up or enumerate user/group records it's sufficient to talk to one service instead of all of them in parallel.
one service instead of all of them in parallel. Note that it is not available Note that it is not available during earliest boot and final shutdown phases, hence for programs running
during earliest boot and final shutdown phases, hence for programs running in that context it is preferable to implement the parallel lookup themselves.
in that context it is preferable to implement the parallel lookup
themselves.
Both these services are implemented by the same daemon Both these services are implemented by the same daemon
`systemd-userdbd.service`. `systemd-userdbd.service`.
Note that these services currently implement a subset of Varlink only. For Note that these services currently implement a subset of Varlink only.
example, introspection is not available, and the resolver logic is not used. For example, introspection is not available, and the resolver logic is not used.
## Other Services ## Other Services
@ -129,35 +125,33 @@ interface. Specifically:
`systemd-machined.service` and provides records for the users and groups used `systemd-machined.service` and provides records for the users and groups used
by local containers that use user namespacing. by local containers that use user namespacing.
Other projects are invited to implement these services too. For example, it Other projects are invited to implement these services too.
would make sense for LDAP/ActiveDirectory projects to implement these For example, it would make sense for LDAP/ActiveDirectory projects to implement these
interfaces, which would provide them a way to do per-user resource management interfaces, which would provide them a way to do per-user resource management
enforced by systemd and defined directly in LDAP directories. enforced by systemd and defined directly in LDAP directories.
## Compatibility with NSS ## Compatibility with NSS
Two-way compatibility with classic UNIX/glibc NSS user/group records is Two-way compatibility with classic UNIX/glibc NSS user/group records is provided.
provided. When using the Varlink API, lookups into databases provided only via When using the Varlink API, lookups into databases provided only via
NSS (and not natively via Varlink) are handled by the NSS (and not natively via Varlink) are handled by the `io.systemd.NameServiceSwitch` service (see above).
`io.systemd.NameServiceSwitch` service (see above). When using the NSS API When using the NSS API (i.e. `getpwnam()` and friends) the `nss-systemd` module will automatically
(i.e. `getpwnam()` and friends) the `nss-systemd` module will automatically synthesize NSS records for users/groups natively defined via a Varlink API.
synthesize NSS records for users/groups natively defined via a Varlink Special care is taken to avoid recursion between these two compatibility mechanisms.
API. Special care is taken to avoid recursion between these two compatibility
mechanisms.
Subsystems that shall provide user/group records to the system may choose Subsystems that shall provide user/group records to the system may choose
between offering them via an NSS module or via a this Varlink API, either way between offering them via an NSS module or via a this Varlink API, either way
all records are accessible via both APIs, due to the bidirectional all records are accessible via both APIs, due to the bidirectional forwarding.
forwarding. It is also possible to provide the same records via both APIs It is also possible to provide the same records via both APIs
directly, but in that case the compatibility logic must be turned off. There directly, but in that case the compatibility logic must be turned off.
are mechanisms in place for this, please contact the systemd project for There are mechanisms in place for this, please contact the systemd project for
details, as these are currently not documented. details, as these are currently not documented.
## Caching of User Records ## Caching of User Records
This API defines no concepts for caching records. If caching is desired it This API defines no concepts for caching records.
should be implemented in the subsystems that provide the user records, not in If caching is desired it should be implemented in the subsystems that provide the user records,
the clients consuming them. not in the clients consuming them.
## Method Calls ## Method Calls
@ -198,16 +192,15 @@ error ConflictingRecordFound()
error EnumerationNotSupported() error EnumerationNotSupported()
``` ```
The `GetUserRecord` method looks up or enumerates a user record. If the `uid` The `GetUserRecord` method looks up or enumerates a user record.
parameter is set it specifies the numeric UNIX UID to search for. If the If the `uid` parameter is set it specifies the numeric UNIX UID to search for.
`userName` parameter is set it specifies the name of the user to search If the `userName` parameter is set it specifies the name of the user to search for.
for. Typically, only one of the two parameters are set, depending whether a Typically, only one of the two parameters are set, depending whether a
look-up by UID or by name is desired. However, clients may also specify both look-up by UID or by name is desired.
parameters, in which case a record matching both will be returned, and if only However, clients may also specify both parameters, in which case a record matching both will be returned, and if only
one exists that matches one of the two parameters but not the other an error of one exists that matches one of the two parameters but not the other an error of `ConflictingRecordFound` is returned.
`ConflictingRecordFound` is returned. If neither of the two parameters are set If neither of the two parameters are set the whole user database is enumerated.
the whole user database is enumerated. In this case the method call needs to be In this case the method call needs to be made with `more` set, so that multiple method call replies may be generated as
made with `more` set, so that multiple method call replies may be generated as
effect, each carrying one user record. effect, each carrying one user record.
The `service` parameter is mandatory and should be set to the service name The `service` parameter is mandatory and should be set to the service name
@ -217,13 +210,12 @@ of multiple services on the same socket (which is used by
`systemd-userdbd.service`). `systemd-userdbd.service`).
The method call returns one or more user records, depending which type of query is The method call returns one or more user records, depending which type of query is
used (see above). The record is returned in the `record` field. The used (see above). The record is returned in the `record` field.
`incomplete` field indicates whether the record is complete. Services providing The `incomplete` field indicates whether the record is complete.
user record lookup should only pass the `privileged` section of user records to Services providing user record lookup should only pass the `privileged` section of user records to
clients that either match the user the record is about or to sufficiently clients that either match the user the record is about or to sufficiently
privileged clients, for all others the section must be removed so that no privileged clients, for all others the section must be removed so that no sensitive data is leaked this way.
sensitive data is leaked this way. The `incomplete` parameter should indicate The `incomplete` parameter should indicate whether the record has been modified like this or not (i.e. it is `true` if a
whether the record has been modified like this or not (i.e. it is `true` if a
`privileged` section existed in the user record and was removed, and `false` if `privileged` section existed in the user record and was removed, and `false` if
no `privileged` section existed or one existed but hasn't been removed). no `privileged` section existed or one existed but hasn't been removed).
@ -233,53 +225,48 @@ specified, and hence enumeration requested but the subsystem currently has no
users defined). users defined).
If a method call with an incorrectly set `service` field is received If a method call with an incorrectly set `service` field is received
(i.e. either not set at all, or not to the service's own name) a `BadService` (i.e. either not set at all, or not to the service's own name) a `BadService` error is generated.
error is generated. Finally, `ServiceNotAvailable` should be returned when the Finally, `ServiceNotAvailable` should be returned when the backing subsystem is not operational for some reason and hence no information
backing subsystem is not operational for some reason and hence no information about existence or non-existence of a record can be returned nor any user record at all.
about existence or non-existence of a record can be returned nor any user (The `service` field is defined in order to allow implementation of daemons that provide multiple distinct user/group services over the same
record at all. (The `service` field is defined in order to allow implementation
of daemons that provide multiple distinct user/group services over the same
`AF_UNIX` socket: in order to correctly determine which service a client wants `AF_UNIX` socket: in order to correctly determine which service a client wants
to talk to, the client needs to provide the name in each request.) to talk to, the client needs to provide the name in each request.)
The `GetGroupRecord` method call works analogously but for groups. The `GetGroupRecord` method call works analogously but for groups.
The `GetMemberships` method call may be used to inquire about group The `GetMemberships` method call may be used to inquire about group memberships.
memberships. The `userName` and `groupName` arguments take what the name The `userName` and `groupName` arguments take what the name suggests.
suggests. If one of the two is specified all matching memberships are returned, If one of the two is specified all matching memberships are returned,
if neither is specified all known memberships of any user and any group are if neither is specified all known memberships of any user and any group are returned.
returned. The return value is a pair of user name and group name, where the The return value is a pair of user name and group name, where the user is a member of the group.
user is a member of the group. If both arguments are specified the specified If both arguments are specified the specified membership will be tested for, but no others, and the pair is returned if it is
membership will be tested for, but no others, and the pair is returned if it is
defined. Unless both arguments are specified the method call needs to be made defined. Unless both arguments are specified the method call needs to be made
with `more` set, so that multiple replies can be returned (since typically with `more` set, so that multiple replies can be returned (since typically
there are multiple members per group and also multiple groups a user is there are multiple members per group and also multiple groups a user is member of).
member of). As with `GetUserRecord` and `GetGroupRecord` the `service` As with `GetUserRecord` and `GetGroupRecord` the `service`
parameter needs to contain the name of the service being talked to, in order to parameter needs to contain the name of the service being talked to, in order to
allow implementation of multiple services within the same IPC socket. In case no allow implementation of multiple services within the same IPC socket.
matching membership is known `NoRecordFound` is returned. The other two errors In case no matching membership is known `NoRecordFound` is returned.
are also generated in the same cases as for `GetUserRecord` and The other two errors are also generated in the same cases as for `GetUserRecord` and
`GetGroupRecord`. `GetGroupRecord`.
Unlike with `GetUserRecord` and `GetGroupRecord` the lists of memberships Unlike with `GetUserRecord` and `GetGroupRecord` the lists of memberships
returned by services are always combined. Thus unlike the other two calls a returned by services are always combined.
membership lookup query has to wait for the last simultaneous query to complete Thus unlike the other two calls a membership lookup query has to wait for the last simultaneous query to complete
before the complete list is acquired. before the complete list is acquired.
Note that only the `GetMemberships` call is authoritative about memberships of Note that only the `GetMemberships` call is authoritative about memberships of users in groups.
users in groups. i.e. it should not be considered sufficient to check the i.e. it should not be considered sufficient to check the
`memberOf` field of user records and the `members` field of group records to `memberOf` field of user records and the `members` field of group records to
acquire the full list of memberships. The full list can only be determined by acquire the full list of memberships.
`GetMemberships`, and as mentioned requires merging of these lists of all local The full list can only be determined by `GetMemberships`, and as mentioned requires merging of these lists of all local services.
services. Result of this is that it can be one service that defines a user A, Result of this is that it can be one service that defines a user A,
and another service that defines a group B, and a third service that declares and another service that defines a group B, and a third service that declares that A is a member of B.
that A is a member of B.
Looking up explicit users/groups by their name or UID/GID, or querying Looking up explicit users/groups by their name or UID/GID, or querying
user/group memberships must be supported by all services implementing these user/group memberships must be supported by all services implementing these interfaces.
interfaces. However, supporting enumeration (i.e. user/group lookups that may However, supporting enumeration (i.e. user/group lookups that may
result in more than one reply, because neither UID/GID nor name is specified) result in more than one reply, because neither UID/GID nor name is specified) is optional.
is optional. Services which are asked for enumeration may return the Services which are asked for enumeration may return the `EnumerationNotSupported` error in this case.
`EnumerationNotSupported` error in this case.
And that's really all there is to it. And that's really all there is to it.