2.21 Conformance

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

2.21.1 Authority obligations #

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

2.21.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.21.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.21.1.3 Conversation #

  1. Require LogonStart, CredentialChangeStart, CredentialEnrollStart, SessionEnd or SessionEndQuery 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.21.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.21.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.21.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.21.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.21.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.21.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.21.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 0x20–0x7e, 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.21.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, and gather a BUILTIN group's recorded members from the sources rather than reporting it Absent (§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.21.1.12 Service attestation #

An authority that implements ServiceAttest MUST satisfy all of the following. An authority that does not implement it MUST refuse the message, and is conforming.

  1. Never hold, store, or accept a credential for a service identity, and never offer a credential exchange for one (§2.19).
  2. Refuse a ServiceAttest unless both the peer's principal and the peer's being the platform's service manager are established from the connection, and never from the message (§2.19).
  3. Answer a peer that satisfies neither condition, or only one, with PermissionDenied (§2.19).
  4. Never mint a token under this message for a principal that has not been designated as usable for a service logon, and refuse with AccountRestricted where it cannot determine whether a principal carries that designation (§2.19).
  5. Never let a refusal distinguish "no such principal" from "not designated for service logon" (§2.19, §2.10).
  6. Reject an empty or unusable service with MalformedRequest (§2.19).
  7. Record the logon type as Service, and leave every profile field empty rather than inventing a value (§2.19, §2.9).
  8. Issue a token that cannot be used to authenticate to another system on the authority's behalf, at a level below the one a credentialled logon receives and bounding everything derived from it (§2.19).
  9. Record that the logon was attested rather than authenticated, wherever it records what vouched for a credentialled logon (§2.19).
  10. Reject a LogonStart that would complete with no credential exchange for an identity it accepts under ServiceAttest, and reject a ServiceAttest naming an identity it accepts under LogonStart (§2.19).

2.21.1.13 Logon type restrictions #

  1. Refuse a logon whose type the principal's holder does not permit, with AccountRestricted, after authentication rather than instead of it (§2.16, §2.10).
  2. Read an unstated LOGON_TYPES as its own default rather than as "nothing permitted", and never include Service in that default (§2.16, §2.19).
  3. Never widen what a principal's holder permits. Local policy may narrow it further; nothing may add to it (§2.16).
  4. Refuse a logon_type it does not recognise, with MalformedRequest (§2.7, §2.10).

2.21.1.14 Credential change #

An authority that implements CredentialChangeStart MUST satisfy all of the following. An authority that does not implement it MUST refuse the message with PermissionDenied, and is conforming. Obligations 10 to 13, 19, 20, 24 and 25 bind a change conversation as they bind a logon.

  1. Change only the credential of the principal the connected peer's token names, established from the socket and never from a message (§2.20, §2.4).
  2. Establish, within the conversation, that the principal can present their current credential before changing it, and refuse with AuthenticationFailed where they cannot (§2.20).
  3. Refuse with AccountRestricted a principal it holds no changeable credential for, including every service identity (§2.20, §2.19).
  4. Send CredentialChanged only once the new credential is the one a subsequent logon will be tested against (§2.20).
  5. Mint no token and create no session for a change, and send no descriptor with CredentialChanged (§2.20).
  6. End with ConversationLimit a change it gives up on for want of an acceptable new credential (§2.20).
  7. Refuse a CredentialChangeStart that ends before supported_credential_types with MalformedRequest (§2.20).
  8. Where the socket's descriptor admits peers that may not originate logons, decide from each peer's identity whether it may originate one, and never treat reaching the socket as that permission (§2.20, §2.4).

2.21.1.15 Ending a session #

An authority that implements SessionEnd and SessionEndQuery MUST satisfy all of the following. An authority that does not implement them MUST refuse both with PermissionDenied, and is conforming. Obligations 5 to 8, 10 and 14 bind these requests as they bind a logon.

  1. Never accept SessionEndQuery as SessionEnd or the reverse, and change nothing in answering SessionEndQuery (§2.22).
  2. Answer SessionEndQuery with SessionEndAllowed exactly where a SessionEnd from the same peer would be permitted, and otherwise with the denial it would draw (§2.22).
  3. Refuse, with PermissionDenied, a peer whose token is restricted, the SYSTEM and Anonymous sessions the kernel creates, and every session of logon type Service, whoever asks (§2.22).
  4. Permit a caller to end a session whose user is the caller, of a logon type a person has, where the caller is a principal of an issued domain (§2.22).
  5. Decide any other request by an access check of the caller's token against a descriptor local policy states — SYSTEM and Administrators alone where it states none, and nobody where it states one that cannot be used (§2.22).
  6. Answer NoSuchSession only to a caller who may end other principals' sessions, and PermissionDenied to any other where the session does not exist (§2.22, §2.10).
  7. End every process whose primary token belongs to the session — asking first, then, after a grace period of at most 10 seconds, without asking — and never a process only because one of its threads impersonates a token of the session (§2.22).
  8. Address each signal by a reference that cannot come to name a different process, never by a process identifier looked up again (§2.22).
  9. Look again after each round, bound the number of rounds, and answer within 30 seconds (§2.22).
  10. Count in remaining every process it could not examine or end, and never fail the request for one (§2.22).
  11. Hold no token of the session longer than it takes to read which session it belongs to, and never end its own process (§2.22).
  12. Where the session is the one the connected peer's token belongs to, send SessionEnded before signalling anything, carrying what it found to end and a remaining of zero (§2.22).
  13. Start nothing in ending a session (§2.1, §2.22).

2.21.1.16 Credential enrolment #

An authority that implements CredentialEnrollStart MUST satisfy all of the following. An authority that does not implement it MUST refuse the message with PermissionDenied, and is conforming. Obligations 10 to 13, 19, 20, 24, 25, 68, 69 and 72 bind an enrolment as they bind a credential change.

  1. Add or remove only the credentials of the principal the connected peer's token names, established from the socket and never from a message (§2.23, §2.4).
  2. For both Add and Remove, establish within the conversation that the principal can present their current credential before changing anything, and refuse with AuthenticationFailed where they cannot (§2.23).
  3. Refuse with AccountRestricted a principal it holds no credential for that it can ask for as proof, including every service identity (§2.23, §2.19).
  4. Refuse an action or credential_type it does not recognise with MalformedRequest, a credential_type it does not enrol with PermissionDenied, and a CredentialEnrollStart that ends before material with MalformedRequest (§2.23).
  5. Refuse material it will not accept with CredentialRejected, check it again when applying the change, and never send CredentialRejected for a failed proof or in answer to any other message (§2.23, §2.B).
  6. Leave unchanged which credentials the principal may sign in with (§2.23).

2.21.2 Client obligations #

There are four client roles, and they are independent. A program may be any of them, several, or none: 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. An implementation changing its own principal's credential MUST satisfy obligations 2 to 12 and 18 to 20, reading CredentialChangeStart wherever they say LogonStart, and 28 and 29. An implementation adding or removing its own principal's credentials MUST satisfy the same, reading CredentialEnrollStart for CredentialChangeStart, and 34 and 35. An implementation ending logon sessions MUST satisfy obligations 4 to 7 and 30 to 33.

2.21.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.21.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.21.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.21.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.21.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.21.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.21.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.21.2.8 Credential change #

  1. Send exactly one CredentialChangeStart, as the first message, and name no principal in it — there is no field for one (§2.20).
  2. Treat CredentialChanged as the only successful outcome, expect no token with it, and close any descriptor that arrives with it (§2.20).

2.21.2.9 Ending a session #

  1. Send exactly one SessionEnd or SessionEndQuery, as the only message, and use SessionEndQuery — never SessionEnd — to learn whether ending a session would be permitted (§2.22).
  2. Wait up to 60 seconds for the answer to SessionEnd before treating it as unanswered, and then not assume either outcome (§2.22).
  3. Treat a non-zero remaining as a session that may still exist, and never read the counts as an outcome where the session was the caller's own (§2.22).
  4. Treat a denial code it does not recognise as a refusal, not as an unreadable answer (§2.B).

2.21.2.10 Credential enrolment #

  1. Send exactly one CredentialEnrollStart, as the first message, with every field, and name no principal in it (§2.23).
  2. Tell CredentialRejected (the material) apart from AuthenticationFailed (the proof) where it reports a refusal, and treat a denial code it does not recognise as a refusal (§2.23, §2.B).

2.21.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