Instantly share code, notes, and snippets.
Created
August 14, 2014 10:55
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save dvdhrm/0c0dba4f5786cf20413a to your computer and use it in GitHub Desktop.
authorityd
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Authority | |
| ========= | |
| The systemd authority infrastructure provides authentication and authorization | |
| services to a system via dbus. Privileged processes can query the | |
| authority-daemon to request authorization on behalf of someone else. In other | |
| words, processes that provide services to unprivileged processes can ask for | |
| authorization of that unprivileged process. Furthermore, in case the | |
| authorization is not granted, you might optionally ask for authentication as a | |
| user with sufficient privileges. | |
| Both, authorization and authentication, can be used independently of each other | |
| and can optionally operate with user-interaction. If you request | |
| user-interaction, the authentication-agents serving the unprivileged process are | |
| asked to allow challenge/response interaction with a user. This can be | |
| graphical, text-based or even external. The restrictions placed on | |
| authentication agents are kept minimal. | |
| As authentication on linux used to be bound to linux-PAM, and PAM is accessible | |
| from root only (via a questionable API that needs multiple threads/processes to | |
| handle multiple authentication methods at once) we also provide a generic API | |
| for providers of authentication methods. The authority-daemon enumerates | |
| available providers and wraps them on the bus. That means, whenever | |
| authentication is requested, the authority-daemon queries available providers | |
| and manages the challenge/response interface between the provider and running | |
| agents. To support more than text-based communication like PAM, an agent has to | |
| explicitly attach to a provider to allow using it. Thus, if you don't have an | |
| agent installed that supports a given provider, this provider will not be used | |
| for any challenge/response interfaces. | |
| The authority infrastructure is modelled around a single daemon, called | |
| "systemd-authorityd". This daemon reads configuration files from the system and | |
| provides an API on the bus. The daemon can run multiple times, once for each bus | |
| you want to provide its services on. The privilege levels managed by the daemon | |
| depend on the bus you run on. That is, if you provide an API on the user-bus and | |
| you ask the local authority-daemon on the same bus to authorize an action | |
| requring root-privileges, you cannot rely on the response to be authoritative. | |
| Problem is, the user-bus is managed and owned by a user. Hence, this user can | |
| control this bus and perform any imaginable attack. Therefore, asking for a | |
| privilege level higher than that of the user is not reliable. Fortunately, if | |
| you provide services on the user-bus, you should never request root-privileges | |
| for those, anyway. Privileged processes should never talk to unprivileged buses | |
| if reliable information is needed. The bus-owner could always spoof the | |
| sender-credentials and thus pretend to be someone else. | |
| Overview | |
| ======== | |
| Involved Actors: | |
| * authorityd: The systemd-authorityd daemon provides authentication and | |
| authorization services via a bus API. | |
| * service-daemon: A service-daemon is a program that provides services to | |
| other programs. Whenever such a service is used by an | |
| untrusted program, it asks authorityd for authorization of | |
| that untrusted program. The API that is used to offer the | |
| service is not bound to dbus. However, the service-daemon | |
| must be able to authoritatively identify the untrusted | |
| program. That is, it has to know the UID, GID, PID or some | |
| other credentials of it. Depending on which credentials it | |
| can reliably retrieve, authorityd can apply different | |
| authorization rules. | |
| * service-client: A service-client is a program that accesses the service | |
| offered by a service-daemon. There is no restriction made | |
| on the privilege level of the service-client, nor on the | |
| communication channel between service-client and | |
| service-daemon. | |
| * agent: Agents provide interactive authentication and/or authorization. | |
| Whenever a request cannot be satisfied immediately, all agents | |
| registered for the given subject are queried to interactively | |
| satisfy the requests. | |
| +--------------------+ +----------------+ | |
| | Unprivileged Agent | | Service Client | | |
| +--------------------+ +----------------+ | |
| ^ ^ | |
| Unprivileged Context | | | |
| =================================|============================|======== | |
| Privileged Context | | | |
| | V | |
| +------------------+ | +----------------+ | |
| | Privileged Agent |<---------+ | +--------------->| Service Daemon | | |
| +------------------+ | | | +----------------+ | |
| | | | | |
| V V V | |
| /-----\ | |
| * Bus * | |
| \-----/ | |
| ^ | |
| | | |
| | | |
| | | |
| V | |
| +------------+ | |
| | authorityd | | |
| +------------+ | |
| API Overview | |
| ============ | |
| The authority-daemon claims the name "org.freedesktop.authority1" on the bus it | |
| is connected to. On this bus, it provides a singleton object reachable as | |
| "/org/freedesktop/authority1" and accessible via the manager interface | |
| "org.freedesktop.authority1.Manager". | |
| Furthermore, the object-manager interface of DBus is used to advertise all | |
| available objects, their supproted interface and their properties. Use it to | |
| enumerate objects, no separate notifications and lists are provided. | |
| The Manager-interface is accessible to unprivileged clients. Depending on the | |
| method and the passed arguments, access may be denied to unprivileged clients. | |
| Usually, you can only invoke methods that only affect your local | |
| session/process/user, in case you're unprivileged. Everyone, who does not have | |
| the same, or a superset of the, privileges of the bus-owner, is considered | |
| unprivileged. | |
| org.freedesktop.authority1.Manager: | |
| * RequestAuthentication(...) | |
| @arg[subject]: A description of the service-client that you want to | |
| request authentication of. | |
| @arg[object]: The object you want the subject to authenticate as. | |
| @arg[flags]: An array of flags modifying the behavior of this call. | |
| @returns: Object-path to an in-flight Authentication object. | |
| This call requests a service-client @subject to authenticate. In case | |
| you are only interested in specific authentications, you can pass it | |
| as @object. | |
| For instance, if @subject is set to a UID and @object is set to | |
| "admin", the given user is asked to authenticate as administrator. | |
| The @flags argument allows to modify the behavior of this call: | |
| "interactive": In case the authentication cannot be performed | |
| automatically, the agents of the user are queried to | |
| perform interactive authentication. | |
| This call always returns immediately and provides an object-path to | |
| an Authentication-object freshly created with a unique name in: | |
| /org/freedesktop/authority1/authentication/<unique-name> | |
| supporting an interface of name: | |
| org.freedesktop.authority1.Authentication | |
| This authentication object is also announced via the object-manager. | |
| If you disabled interactivity, this object may be destroyed | |
| immediately after it was created. Therefore, you must handle the | |
| announcements of the object-manager (which includes properties) if you | |
| want the information provided by that object. | |
| * RequestAuthorization(...) | |
| @arg[subject]: A description of the service-client that you want to | |
| request authorization for. | |
| @arg[action]: The action you want the subject to be authorized for. | |
| @arg[flags]: An array of flags modifying the behavior of this call. | |
| @returns: Object-path to an in-flight Authorization object. | |
| This is very similar to RequestAuthentication(), but instead of asking | |
| @subject to authenticate, it asks, whether @subject is authorized to | |
| do the action specified by @action. | |
| The @flags argument allows to modify the behavior of this call: | |
| "interactive": In case the subject is not authorized to perform the | |
| action, but the action itself defines a required | |
| authentication level, this will query the agents of | |
| the user to perform interactive authentication to | |
| gain required privilege levels. | |
| This call always returns immediately and provides an object-path to | |
| an Authorization-object freshly created with a unique name in: | |
| /org/freedesktop/authority1/authorization/<unique-name> | |
| supporting an interface of name: | |
| org.freedesktop.authority1.Authorization | |
| * AddAgent(...) | |
| TBD | |
| * RemoveAgent(...) | |
| TBD | |
| Whenever you perform an authentication, we create an in-flight "Authentication" | |
| object. It lives as long as the authentication takes. So in case it's | |
| non-interactive, it is usually destroyed before the call to | |
| RequestAuthentication() returns. This is fine, though. The object is only used | |
| as transmitter of data for such authentications. Therefore, the object-manager | |
| makes sure all properties are advertised with their value included. No need for | |
| clients to ever query any properties. | |
| However, if you use interactive authentication, the object will be kept until | |
| authentication is done (or canceled). Thus, you can query the object (or even | |
| call methods on it) while it's in-flight. Same applies to objects of type | |
| "Authorization". | |
| org.freedesktop.authority1.Authentication: | |
| * Property: Subject | |
| The subject describes who is performing this authentication. | |
| * Property: Object | |
| The Object defines what you're authenticating as. It's copied | |
| unchanged from the RequestAuthentication() call. | |
| * Property: Authorization | |
| This contains the object path of the authorization this is running | |
| for. In case this is not part of an authorization, this is an empty | |
| path. | |
| * Cancel(...) | |
| This cancels an interactive authentication with immediate effect. | |
| * Signal: Done(...) | |
| This is sent once the authentication is done. The object is destroyed | |
| immediately after this signal is generated. The signal carries | |
| information about success/failure of the authentication. The actual | |
| object you authenticated as, can be found in @object and is kept | |
| up-to-date by authorityd. | |
| org.freedesktop.authority1.Authorization: | |
| * Cancel(...) | |
| This cancels an interactive authorization with immediate effect. | |
| * Signal: Done(...) | |
| This is sent once the authorization is done. The object is destroyed | |
| immediately after this signal is generated. The signal carries | |
| information about success/failure. | |
| Whenever an authorization cannot be granted immediately, we optionally perform | |
| an authentication of the user in question to grant more privileges. Furthermore, | |
| clients can request authentications without any previous authorization request. | |
| All those authentications usually require interactivity. In those cases, agents | |
| perform the interaction with users. | |
| Agents can be registered privileged or unprivileged: | |
| * If there is an authority instance running on the system bus, each user | |
| session usually registers their own agent so password-prompts can be shown | |
| on the screen. Those agents run as the user, thus, they are less privileged | |
| than the system-bus authorityd instance. Therefore, they're considered | |
| unprivileged clients. | |
| Those agents can be used for authentication methods that can be verified by | |
| the authority daemon. For instance, password-entries are just fine as those | |
| passwords are verified by the authority. However, an authentication method | |
| just just shows two buttons with "Allow this action? Yes/No" cannot be used | |
| with unprivileged agents as the authority daemon cannot verify which button | |
| was actually pressed. | |
| Agents are always limited to a subject. That means, you specify which subjects | |
| you serve and then the agent is only used for requests from that subject. This | |
| guarantees that an unprivileged user agent is only ever asked for | |
| authentications performed by exactly that user. | |
| Agents do not perform any authentication themselves. They only serve as | |
| interface to interact with users and/or hardware. The actual authentication | |
| methods are defined by providers. An agent needs to attach to providers it wants | |
| to support. Once an authentication is started, those providers will send | |
| notifications to the agent, what to do. Usually, this involves | |
| challenge/response kinda things, but is not limited to that. The agent performs | |
| the action and then forwards the response to the provider. | |
| The interface between authorityd and those providers is not part of this | |
| specification. For now, providers are built-in. One provider just uses PAM as | |
| backend, so you can use your known PAM modules. We might want to allow external | |
| providers at some point, though. | |
| org.freedesktop.authority1.Agent: | |
| * Property: Subject | |
| The subject defines who this agent is running for and which subjects | |
| serving. Only matching authentication requests are forwarded to this | |
| agent. | |
| * Property: Privileged | |
| This property specifies the privilege level of the agent. Usually, | |
| agents need to run privileged, however, there are some exceptions | |
| where agents might run unprivileged. Note that some providers require | |
| privileged agents. | |
| * Property: Language | |
| This is a writable property. Whenever an agent changes it's UI | |
| language, it should adjust this property so providers can resend | |
| information in translated form. | |
| * Signal: StartAuthentication(...) | |
| This is sent whenever a new authentication is started. The payload | |
| contains the object-path of the authentication object. | |
| * Signal: StopAuthentication() | |
| This is sent whenever a new authentication is stopped. The payload | |
| contains the object-path of the authentication object. Note that only | |
| one authentication can be active at a time on a single agent. | |
| org.freedesktop.authority1.Provider: | |
| * Property: Name | |
| A name (usually an interface-name) that identifies the type of this | |
| provider. It also defines the API used to communicate with this | |
| provider. | |
| * Attach(...) | |
| All available providers can be enumerated by registered agents. As an | |
| agent often does not know how to talk to a given provider, they are | |
| not enabled automatically. Instead, an agent needs to attach to a | |
| provider in case it knows how to talk to it. | |
| Once attached, the provider will send ShowMessage/Challenge signals | |
| to the agent. | |
| * Detach(...) | |
| This detaches an agent from a provider again. | |
| * Respond(...) | |
| Once a challenge-message was printed and a user reacted to it, the | |
| agent has to forward that response to the provider. The exact format | |
| depends on the type of the provider. | |
| * Signal: ShowChallenge(...) | |
| This asks an agent to show a challenge-message to the user. The exact | |
| format of the message depends on the provider. It may be a string, but | |
| may also be an ENUM that is left to the interpretation of the agent. | |
| The format is part of the provider's API and it's their job to not | |
| break it. | |
| * Signal: ShowMessage(...) | |
| This asks an agent to show a message to the user. The exact format of | |
| the message depends on the provider. It may be a string, but may also | |
| be an ENUM that is left to the interpretation of the agent. | |
| The format is part of the provider's API and it's their job to not | |
| break it. | |
| Examples | |
| ======== | |
| 1) Desktop-Session | |
| On desktop-sessions, you can simply register your unprivileged agent as you | |
| did with polkit. It will attach to the PAM provider and simply shows requests | |
| on the screen and asks for input. | |
| 2) Password Provider | |
| The default provider uses PAM as backend. We forward the challenge/response | |
| strings to the agent so they can deal with this crap. We use a pam-policy | |
| similar to polkit-1. For all advanced stuff which is not user/password, I | |
| want separate providers as PAM really sucks for those. | |
| 3) Fingerprint | |
| A simple provider that directly talks to the fingerprint deamon (see fdo). It | |
| does *not* do challenge/response but only forwards status messages to the | |
| agent. In case the agent supports this provider, it can print messages like | |
| "finger moved to fast", "finger moved in wrong direction", and so on. And it | |
| can also show some UI images instead of just text-messages. | |
| Note that this provider works even if an agent is not attached. This is | |
| really handy as you can authenticate without the agent knowing you used | |
| fingerprint. Obviously, for status messages the agent really *should* support | |
| it, though. | |
| 4) SAK | |
| If we want secure-attention-key support, we need *privileged* agents. That | |
| is, the usual user-session agent does not work for that. Instead, there's a | |
| separate system agent which runs privileged. Whenever the SAK key is pressed | |
| we force-switch to it. This allows users to use their session-level agent if | |
| they don't care, but once the SAK key is pressed, we switch to the privileged | |
| system agent. | |
| For now, the system-agent will have a hard time looking good as it has no way | |
| to access the session content. Therefore, it will probably much look like | |
| switching to gdm. | |
| 5) Apps | |
| We want to support authorization on multiple buses. Apps are one example. | |
| Therefore, if you run the authority daemon on the user-bus and Apps ask for | |
| authorization to access user-privileged data, we can tell agents to print | |
| dialogs like "Allow this App to do this? Yes/No". | |
| In this case, the agent runs in the user-session itself and it is considered | |
| PRIVILEGED! It runs as the same privilege level as the authority daemon so it | |
| is privileged. Therefore, the authority daemon can rely on its responses. A | |
| simply Yes/No question is thus allowed. | |
| Note that this only works because this is the authority daemon running on the | |
| user-bus. | |
| An unprivileged agent in this case would be an agent registered by the App | |
| itself. This agent obviously cannot be trusted, so it can *not* be asked to | |
| perform Yes/No questions. However, in case the App talks to the system-bus | |
| authority daemon (eg., to change hostnames), it can register it's own agent | |
| to perform fingerprint based authentication. An unprivileged agent is just | |
| fine. Note that we probably don't want to allow doing password-based | |
| authentication for unprivileged agents on that level. The App would gain | |
| access to the plaintext password of the user, which is Bad. | |
| On the user-session level, this is bad, too, but we usually expect the user | |
| to trust itself, so we allow it so far. But maybe we should rethink that, | |
| too. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment