2.19 Conformance

A conforming implementation MUST satisfy every requirement in this chapter. This section collects them by role.

2.19.1 Authority obligations #

An implementation claiming to be a PGSS Logon authority MUST satisfy all of the following.

2.19.1.1 Channel #

  1. Listen on /run/logon.sock as a SOCK_STREAM Unix domain socket (§2.5).
  2. Control access to it with a security descriptor, not with process integrity and not with POSIX permission bits (§2.4).
  3. Serve conversations concurrently, so that one stalled logon does not block others (§2.5).
  4. Support SCM_RIGHTS on the channel (§2.9).

2.19.1.2 Framing #

  1. Reject any message whose magic is not PGSL, as a whole-connection failure (§2.6).
  2. Reject any message whose version it does not implement, answering UnsupportedVersion where it can still encode a denial (§2.6).
  3. Reject any message declaring more than 65536 bytes, or fewer than a header, without reading the body (§2.6).
  4. Skip to a structure's declared end after reading known fields, rather than assuming its length, and substitute a documented default for an optional trailing field a peer did not write (§2.6).

2.19.1.3 Conversation #

  1. Require LogonStart as the first message, and reject a conversation opening otherwise (§2.3).
  2. Send exactly one terminal message, nothing after it, and close the connection (§2.3).
  3. Bound the number of rounds, the time spent awaiting an answer, and the time a conversation may remain open, and terminate with ConversationLimit on exhausting any of them (§2.3, §2.5). A bound reached MUST produce a terminal message; closing the connection silently is what the code exists to prevent.
  4. Reject a CredentialResponse it did not solicit (§2.3).
  5. Match answers to prompts by credential_ref, never by position, and treat a missing answer as a failed logon rather than as grounds to tear down the connection (§2.8).

2.19.1.4 Trust #

  1. Establish peer identity from the connected socket's peer token, never from a message body, and never via SO_PEERCRED (§2.4).
  2. Treat logon_type as a proposal and constrain it against the verified peer (§2.4).
  3. Treat identifier, tty and remote_host as unverified claims (§2.4).

2.19.1.5 Derivation #

  1. Perform derivation itself, and never accept a token, privilege set or integrity level from another party (§2.1).
  2. Never fork or exec on the client's behalf; never learn about terminals, environments or session leadership (§2.1).

2.19.1.6 Prompting #

  1. Never send a prompt for a credential type absent from the client's supported_credential_types, and deny the logon instead if it cannot proceed within them (§2.8).
  2. Ensure credential_ref is unique among the prompts of one request (§2.8).

2.19.1.7 Result #

  1. Transfer the token as a file descriptor in the ancillary data of AccessGranted, never by name (§2.9).
  2. Never distinguish an unknown principal from a bad credential — by denial code, by reason text, or by timing (§2.10, §2.12).
  3. Send home and shell as absolute paths, or empty, whatever their provenance; an authority with no value for a profile field MUST leave it empty rather than invent one (§2.9).

2.19.1.8 Credential handling #

  1. Erase credential material, and every buffer it was encoded and decoded through — including an allocation abandoned by a buffer that grew — before that memory is released (§2.12).
  2. Never write credential material to a log, audit record, error message or diagnostic (§2.12).

2.19.1.9 Identity lookup #

  1. Listen on /run/ident.sock as well as /run/logon.sock, as a SOCK_STREAM Unix domain socket (§2.14).
  2. Grant connect access to that socket, by security descriptor, to every principal that runs ordinary programs (§2.14).
  3. Refuse a message of one socket's range received on the other (§2.14).
  4. Echo each request's tag, and never interpret it otherwise (§2.14).
  5. Serve requests concurrently, and never let a slow answer on one connection delay another (§2.14).
  6. Bound the time spent answering a request, and answer Unavailable rather than waiting indefinitely (§2.14).
  7. Ignore ancillary data received on the identity socket (§2.14).

2.19.1.10 Resolution #

  1. Interpret names itself, and never require a client to parse, qualify or case-fold one (§2.15).
  2. Compare names ASCII case-insensitively, establishing the comparison itself rather than delegating it to a source (§2.15).
  3. Refuse a name containing a reserved character, a byte outside 0x200x7e, or a leading or trailing space — whether created locally, received in a request, asserted by a source, or carried alongside a SID in a reference (§2.15).
  4. Resolve bare names in a configured order, never in registration order, stopping at the first source that answers (§2.15).
  5. Carry the resolved SID and the canonical qualified name on every successful reply, whatever form the request used (§2.15).

2.19.1.11 Answers #

  1. Never answer a Principal request with a group, or a Group request with a principal, and establish the kind itself rather than relaying a source's (§2.16).
  2. Ignore a field bit it does not implement, and never report it as present (§2.16).
  3. Report each requested field it implements as present or as withheld with a reason, never as neither (§2.16).
  4. Withhold MEMBERS with a reason rather than returning a partial or empty list, where it will not or cannot produce it (§2.16).
  5. Report Absent rather than Declined for a group whose membership is a rule rather than a record (§2.16).
  6. Encode "no POSIX identifier" as zero, and never substitute a number a caller could mistake for a real one (§2.16).
  7. Answer a passwd record, a group record, a principal's memberships, or a name for a SID, each in one request (§2.16).
  8. Never report NotFound unless every source in the search order that could have answered was consulted and answered (§2.18).
  9. Report Unavailable where a source earlier in the search order could not be reached (§2.18).
  10. Never report NotFound in place of Refused or of a Restricted field, and never report Refused for anything other than a caller that may not make the request (§2.18).
  11. List every source that did not contribute to an enumeration, and never report Found on a page it could not produce (§2.17, §2.18).
  12. Reject a cursor it did not issue, or can no longer honour, with Malformed — never by restarting the walk and never by reporting it complete (§2.17).
  13. Serve member enumeration where it withholds MEMBERS as TooLarge (§2.17).

2.19.2 Client obligations #

There are two client roles, and they are independent. A program may be either, both, or neither: a logon originator never looks a principal up; a name resolver does the reverse.

An implementation originating logons MUST satisfy obligations 1 to 20. An implementation performing identity lookup MUST satisfy 21 to 27.

2.19.2.1 Conversation #

  1. Send exactly one LogonStart, as the first message (§2.3).
  2. Answer each CredentialRequest with exactly one CredentialResponse (§2.3).
  3. Never send a CredentialResponse that was not solicited (§2.3).
  4. Treat a connection that closes without a terminal message as a failed logon, and not retry automatically (§2.3).

2.19.2.2 Framing #

  1. Reject any message whose magic is not PGSL (§2.6).
  2. Reject any message whose version it does not implement (§2.6).
  3. Skip to a structure's declared end after reading known fields (§2.6).

2.19.2.3 Capabilities #

  1. Never declare in supported_credential_types a credential type it cannot render (§2.7). Declaring fewer than it can render is permitted, and an empty list is how a client asks for a logon requiring no interaction.
  2. Fail the conversation, rather than guess, if it receives a prompt it cannot render (§2.8).

2.19.2.4 Rendering #

  1. Display received messages, in order, before the prompts of the same request (§2.8).
  2. Not interpret or branch on message text, credential_name, or reason (§2.8, §2.10).
  3. Echo credential_ref back unchanged (§2.8).

2.19.2.5 Result #

  1. Read the token descriptor from the ancillary data of AccessGranted, and treat an AccessGranted without one as a failed logon (§2.9).
  2. Close the descriptor if it does not install the token (§2.9).
  3. Have a fallback for every profile field, and treat an empty field, and an absent profile, identically and not as an error (§2.9).
  4. Never execute a relative shell, nor resolve a relative home against its own working directory (§2.9). A shell containing no separator is relative, and MUST NOT be resolved against a search path.
  5. Never treat profile as a directory lookup, nor cache it as an answer about any principal other than the one who just authenticated (§2.9).

2.19.2.6 Credential handling #

  1. Collect a credential only where it can establish that its collection method meets the type's requirements, and never collect a Password with echo enabled (§2.12).
  2. Never silently truncate an answer to fit its own buffer (§2.12).
  3. Erase credential material, and every buffer it was collected and encoded through, before that memory is released, and never write it to a log, error message or diagnostic (§2.12).

2.19.2.7 Identity lookup #

  1. Forward a name unchanged, and never parse, split, qualify or case-fold one (§2.15).
  2. Never reuse a tag while a request bearing it is outstanding, and never assume replies arrive in request order (§2.14).
  3. Treat a cursor as opaque: never construct, parse or modify one, nor present one to a different authority or across a reconnection (§2.17).
  4. Continue an enumeration until next is empty, never infer completion from an empty page, and never present a walk it abandoned for any other reason as a complete one (§2.17).
  5. Surface an enumeration's incomplete list rather than discarding it (§2.17).
  6. Distinguish NotFound from Unavailable, and never cache the second as though it were the first (§2.18).
  7. Never use enumeration to test whether a principal exists (§2.17).

Obligations 24 and 26 bind a client that caches for the lifetime of a single process just as they bind an authority. A resolver that remembers "no such user" through an outage will keep reporting it after the outage ends, and one that reports a failed walk as an empty system does the same thing to every principal at once.

2.19.3 What a client is not required to do #

A client is not required to understand what any credential type means, what any message says, or why a logon was denied. It renders what it is given and returns what it collects.

That is the property the whole conversational shape exists to produce, and a client that starts reasoning about the content of prompts has given it up — it will need changing the next time an authority's policy does.

Edit this page