4.7 Authorising a Command

Every command is authorised against a Security Descriptor, using the peer's token. There is no command the manager performs without a check, and no principal exempt from one.

4.7.1 Rights #

Commands acting on a service are checked against that service's descriptor:

RightBitGrants
SERVICE_QUERY_STATUS0x0001Query the service's state and detail.
SERVICE_START0x0002Start the service.
SERVICE_STOP0x0004Stop the service.
SERVICE_INTERROGATE0x0008Reload the service.
SERVICE_ALL_ACCESS0x000FAll four.

Commands acting on a submitted job are checked against that job's own descriptor, with the rights and generic mapping §7.8 defines: JOB_QUERY (0x0001), JOB_STOP (0x0002), JOB_SIGNAL (0x0004).

Commands acting on the system are checked against the manager's own descriptor:

RightBitGrants
SYSTEM_SHUTDOWN0x0001Initiate a shutdown.
SYSTEM_RELOAD_CONFIG0x0002Re-read the configuration.
SYSTEM_QUERY_STATUS0x0004Ask how the machine booted (boot).

4.7.2 Generic mappings #

The manager MUST use these generic mappings when evaluating a descriptor, so that a descriptor written in generic terms means the same thing to every implementation.

For a service descriptor:

Generic rightMaps to
GENERIC_READSERVICE_QUERY_STATUS
GENERIC_WRITESERVICE_START | SERVICE_STOP | SERVICE_INTERROGATE
GENERIC_EXECUTESERVICE_START | SERVICE_STOP | SERVICE_INTERROGATE
GENERIC_ALLSERVICE_ALL_ACCESS

For the manager's descriptor:

Generic rightMaps to
GENERIC_READSYSTEM_QUERY_STATUS
GENERIC_WRITESYSTEM_RELOAD_CONFIG
GENERIC_EXECUTESYSTEM_SHUTDOWN
GENERIC_ALLSYSTEM_SHUTDOWN | SYSTEM_RELOAD_CONFIG | SYSTEM_QUERY_STATUS

GENERIC_READ maps to the one right on the manager's descriptor that changes nothing, as it maps to SERVICE_QUERY_STATUS on a service.

4.7.3 Per command #

CommandRight required
startSERVICE_START
stopSERVICE_STOP
restartSERVICE_START and SERVICE_STOP
reloadSERVICE_INTERROGATE
resetSERVICE_STOP
statusSERVICE_QUERY_STATUS
listEvaluated per service; see below
operation-statusSERVICE_QUERY_STATUS on the operation's target
job-statusJOB_QUERY on the job
job-listEvaluated per job; see below
job-stopJOB_STOP on the job
shutdownSYSTEM_SHUTDOWN
reload-configSYSTEM_RELOAD_CONFIG
bootSYSTEM_QUERY_STATUS

boot is checked like any other command, although what it reports is not a secret: a descriptor decides who may ask, and §4.15 asks that the default one let every authenticated principal.

reset requires SERVICE_STOP because clearing a terminal state is the tail of stopping something rather than the head of starting it.

4.7.4 The sequence #

  1. If the manager is shutting down, apply §4.15's restriction. The shutdown restriction is evaluated before the access check, so a caller who would have been denied is told the command is invalid for the current state. A client MUST NOT infer anything about its own rights from an INVALID_STATE received during shutdown.
  2. Resolve the target. A command naming no service the manager knows of MUST be answered UNKNOWN_SERVICE. The manager MUST NOT synthesise a descriptor for a service that does not exist.
  3. Evaluate the access check with the peer's token, the target's descriptor, the appropriate generic mapping, and the required right, naming the target in the check's audit context (PGSS §6.7).
  4. On denial, answer ACCESS_DENIED. The attempt is recorded by the access check itself, under the target descriptor's SACL, with the caller, the target and the rights requested and granted; the manager MUST NOT write an access-denied event of its own (PGSS §6.7). A descriptor the manager supplies by default MUST carry a SACL that audits every refusal, so that a denial is not silent unless a descriptor someone wrote says so.
  5. On grant, proceed.

A status, and each job view on this channel, also tells the caller which of these rights it holds on the target, as granted (§4.14). The manager finds them with this same check, asking for MAXIMUM_ALLOWED in step 3 instead of the command's right. That check is a question asked on the caller's behalf, not a command: a right it does not grant is left out of granted, and it is not a denial for step 4.

4.7.5 Filtering rather than denying #

list MUST return only the services the caller may query, and MUST omit the rest rather than denying the command. A caller with no query rights on anything receives an empty list and a successful response.

The response does not say whether services were omitted. What the filtering protects is each service's state, which is what SERVICE_QUERY_STATUS grants, and not whether the service exists: a command naming a service is answered UNKNOWN_SERVICE or by its access check according to whether it exists (step 2 above), and §4.10 does not hide existence either. A client MAY therefore learn from elsewhere which services are defined and show the ones list left out as ones whose state the caller may not see.

job-list MUST be filtered the same way, by JOB_QUERY on each job, and MUST NOT reveal that jobs were omitted.

4.7.6 Not revealing what a caller may not see #

A service's existence is not protected (above). Where a command names an operation the caller may not query, the manager MUST NOT let the answer distinguish "this does not exist" from "you may not see this".

For operation-status this means the authorisation check MUST be evaluated before the operation's existence is reported: a caller lacking SERVICE_QUERY_STATUS on an operation's target MUST receive ACCESS_DENIED whether or not the identifier names a real operation, and MUST NOT receive UNKNOWN_OPERATION for one that exists.

Where the caller's rights cannot be established because the target cannot be resolved, UNKNOWN_OPERATION is the correct answer.

For job-status and job-stop the rule is §7.10's, not this one: a job identifier is unguessable, so a caller that names one was told it, and the manager answers UNKNOWN_JOB for an identifier that names nothing and ACCESS_DENIED for one that names a job the caller may not touch.

Edit this page