2.16 Lookup
One request answers every question a name resolver asks.
2.16.1 Lookup #
msg_type = 0x0010. Client to authority.
| Field | Encoding | Limit |
|---|---|---|
tag | u32 | §2.14 |
key_type | u8 | §2.B |
name | string | 256 bytes |
sid | length-framed bytes (SID) | 68 bytes |
unix_id | u32 | |
kind | u8 | §2.B |
fields | u32 | §2.B |
Exactly one of name, sid and unix_id is meaningful, selected by
key_type. An encoder MUST leave the others empty or zero, and a
decoder MUST ignore them.
2.16.1.1 key_type #
| Value | Name | Answers |
|---|---|---|
| 1 | Name | getpwnam, getgrnam |
| 2 | Sid | Rendering a security descriptor |
| 3 | UnixId | getpwuid, getgrgid |
UnixId is a key even though no source is ever asked one. An
authority converts the number to a source and a relative identifier by
the range arithmetic it assigned, and asks that source by relative
identifier or by SID.
A source therefore never receives an absolute number here, exactly as it never receives one during a logon. The property that made the authority the only possible answerer (§2.13) is the same property that keeps this side of it confined.
2.16.1.2 kind #
| Value | Name |
|---|---|
| 0 | Any |
| 1 | Principal |
| 2 | Group |
A request for Principal MUST NOT be answered with a group, and a
request for Group MUST NOT be answered with a principal. Where the key
matches only an object of the other kind, the outcome is NotFound
(§2.18).
An authority MUST establish this for itself. Where the object came from a source, the authority MUST check the kind it received against the kind that was asked for, rather than relaying the source's answer and letting the client discover the mismatch.
2.16.1.3 fields #
A bitmask of the attributes the reply should carry. Identity is not among them: every successful reply carries the SID, the canonical qualified name, and the kind actually found, and a client cannot decline them.
| Bit | Name | Value encoding |
|---|---|---|
| 0 | UNIX_ID | u32 |
| 1 | PRIMARY_GROUP | reference |
| 2 | HOME | string, 4096 bytes |
| 3 | SHELL | string, 4096 bytes |
| 4 | DISPLAY_NAME | string, 256 bytes |
| 5 | GROUPS | array of references, 128 |
| 6 | MEMBERS | array of references, 256 |
| 7 | CLAIMS | array of claim entries, 64 |
| 8 | ENABLED | u8 |
| 9 | LOGON_TYPES | u32 |
| 10 | DESCRIPTION | string, 1024 bytes |
An authority MUST ignore a bit it does not implement, and MUST NOT report it (below). Claim entries use the claim attribute format PCDS §5.9 specifies.
LOGON_TYPES is a bitmask over the logon type values of §2.B: bit n
set means the principal may be used for logon type n. Zero means the
holder states nothing, not that nothing is permitted — a source that
predates the field sends zero, and an authority that read that as "no
logon permitted" would lock every principal on every existing system out
at once.
An authority substituting a default for zero MUST NOT include Service
in it. A principal that has never said how it may be used has certainly
not said it may be used for a credential-free service logon (§2.19).
DESCRIPTION says what a group is for, in words for a person to read,
on one line. A group with none is answered with an empty string: it has
no description, which is an answer. A principal has none, and the field
is withheld as Absent (below). An authority answers it for its own
well-known groups as well as relaying a source's.
Requesting only what is wanted is not primarily a bandwidth measure — a
getpwuid wants nearly every field anyway. It matters for the caller
that resolves a dozen SIDs to render a security descriptor and wants
only names, and it is the seam at which an authority can restrict
individual fields without restricting the socket (§2.14).
2.16.2 LookupReply #
msg_type = 0x8010. Authority to client.
| Field | Encoding | Limit |
|---|---|---|
tag | u32 | §2.14 |
outcome | u8 | §2.B |
sid | length-framed bytes (SID) | 68 bytes |
qualified_name | string | 512 bytes |
kind_found | u8 | §2.B |
present | u32 | §2.B |
withheld | array of withheld entries | 32 |
values | array of length-framed values | 32 |
Where outcome is not Found, everything after it MUST be empty or
zero, and a client MUST NOT read it.
kind_found MUST be Principal or Group, never Any.
2.16.2.1 present, withheld and values #
values holds one length-framed value for each bit set in present, in
ascending bit order. Each is length-framed so that a client can step
over a value whose field it does not recognise.
Every bit set in the request is in exactly one of three states:
- set in
present— its value is invalues; - listed in
withheld— with a reason, below; - in neither — this authority does not implement the field.
The third state is a statement about the authority, not about the
object. An authority that implements a field MUST place every request
for it in one of the first two states, whatever happened underneath: a
field an authority supports but could not obtain is Absent,
Declined, Restricted or TooLarge, never silence. Reporting it as
neither would tell the client the authority cannot answer that question
at all, and a client is entitled to stop asking.
A withheld entry is a length-framed structure:
| Reason | Meaning |
|---|---|
Absent | The field has no value. |
Restricted | The caller may not have this field. |
Declined | The source will not produce it. |
TooLarge | It exists and exceeds one reply. Use Enumerate (§2.17). |
Distinguishing these is the point of the structure. An empty member list and a source that refuses to enumerate members are the same bytes to a POSIX caller, and an administrator diagnosing a system needs to know which one happened.
2.16.2.2 References #
PRIMARY_GROUP, GROUPS and MEMBERS carry references rather than
bare SIDs:
| Field | Encoding | Limit |
|---|---|---|
sid | length-framed bytes (SID) | 68 bytes |
name | string | 512 bytes |
unix_id | u32 |
An empty name means the authority has no name for that SID; a
unix_id of zero means it has no number for it. Both are ordinary
answers for a SID belonging to no source on this machine.
Zero is the only encoding of "no number". An authority MUST NOT
substitute a POSIX identifier that a caller could mistake for a real
one — a projection onto nobody is a rendering decision belonging to
whatever produces a passwd record, and putting it on the wire
destroys the distinction the client needs in order to make it.
Carrying the name is what keeps the round-trip discipline below intact.
A reply of bare SIDs would make a single getgrnam into one request
plus one per member.
2.16.3 Memberships #
GROUPS on a principal is the membership question, and it is the
direction sources actually hold — the same one a logon uses. An
authority MUST answer it whenever it can answer anything about the
principal at all.
MEMBERS on a group is the reverse index, and it is not owed the same
guarantee.
An authority MUST return MEMBERS as withheld, rather than as an error
or an empty list, when it will not or cannot produce it:
Declinedwhere the source will not enumerate the group's members.TooLargewhere the membership exceeds what one reply can carry.Absentwhere the group is not one that has recorded members at all.
That last case is not a limitation. A group's membership may be
recorded — held by a source, as a local group's is — or it may be a
rule an authority applies when it derives a token. Nothing records
who belongs to Everyone; an authority adds it to every token it mints.
Groups reflecting how a principal signed in are further still from a
recorded membership: they are properties of a logon rather than of a
principal, and the same principal is in one at a console and not over a
network.
An authority MUST report Absent for such a group rather than
manufacturing a list, and MUST NOT report Declined, which would
suggest an answer exists somewhere.
2.16.3.1 The BUILTIN groups #
The BUILTIN groups (S-1-5-32-…, such as Administrators, Users
and Guests) are well-known, and the authority answers for them
itself (§2.15), but their membership is recorded, not a rule.
"jack is in Administrators" is a record a source keeps on this
machine's behalf (PSPU §2.19), as it keeps a local group's.
For MEMBERS on a BUILTIN group, an authority MUST therefore gather
the members each source records, from every source in its search order
that is permitted to assert memberships outside its domain (PSPU §2.19),
and MUST NOT report Absent. A source without that permission records
none that a token would carry, and is not asked.
- Where every such source answered and the list fits one reply, the members are present, in source order.
- Where it will not fit,
MEMBERSis withheld asTooLarge, and the members are walked withEnumerate(§2.17). - Where a source in the order could not be reached, or would not
enumerate,
MEMBERSis withheld asDeclined. A list missing one source's members would look complete.
2.16.4 One round trip #
An authority MUST be able to answer each of the following in a single request:
| Caller wants | Request |
|---|---|
A passwd record | Lookup{key_type: UnixId or Name, kind: Principal, fields: UNIX_ID | PRIMARY_GROUP | HOME | SHELL | DISPLAY_NAME} |
A group record | Lookup{key_type: UnixId or Name, kind: Group, fields: UNIX_ID | MEMBERS} |
| A principal's groups | Lookup{key_type: Name, kind: Principal, fields: GROUPS} |
| A name for a SID | Lookup{key_type: Sid, kind: Any, fields: 0} |
This is a design constraint on future revisions as much as a statement about this one. A name resolver is called from every process on the system, synchronously, and a field that cannot be fetched alongside the record it belongs to turns one lookup into several.