2.16 Lookup

One request answers every question a name resolver asks.

2.16.1 Lookup #

msg_type = 0x0010. Client to authority.

FieldEncodingLimit
tagu32§2.14
key_typeu8§2.B
namestring256 bytes
sidlength-framed bytes (SID)68 bytes
unix_idu32
kindu8§2.B
fieldsu32§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 #

ValueNameAnswers
1Namegetpwnam, getgrnam
2SidRendering a security descriptor
3UnixIdgetpwuid, 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 #

ValueName
0Any
1Principal
2Group

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.

BitNameValue encoding
0UNIX_IDu32
1PRIMARY_GROUPreference
2HOMEstring, 4096 bytes
3SHELLstring, 4096 bytes
4DISPLAY_NAMEstring, 256 bytes
5GROUPSarray of references, 128
6MEMBERSarray of references, 256
7CLAIMSarray of claim entries, 64
8ENABLEDu8

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.

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.

FieldEncodingLimit
tagu32§2.14
outcomeu8§2.B
sidlength-framed bytes (SID)68 bytes
qualified_namestring512 bytes
kind_foundu8§2.B
presentu32§2.B
withheldarray of withheld entries32
valuesarray of length-framed values32

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 in values;
  • 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:

FieldEncodingLimit
fieldu32one bit, §2.B
reasonu8§2.B
ReasonMeaning
AbsentThe field has no value.
RestrictedThe caller may not have this field.
DeclinedThe source will not produce it.
TooLargeIt 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:

FieldEncodingLimit
sidlength-framed bytes (SID)68 bytes
namestring512 bytes
unix_idu32

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:

  • Declined where the source will not enumerate the group's members.
  • TooLarge where the membership exceeds what one reply can carry.
  • Absent where 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.4 One round trip #

An authority MUST be able to answer each of the following in a single request:

Caller wantsRequest
A passwd recordLookup{key_type: UnixId or Name, kind: Principal, fields: UNIX_ID | PRIMARY_GROUP | HOME | SHELL | DISPLAY_NAME}
A group recordLookup{key_type: UnixId or Name, kind: Group, fields: UNIX_ID | MEMBERS}
A principal's groupsLookup{key_type: Name, kind: Principal, fields: GROUPS}
A name for a SIDLookup{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.

Edit this page