Restricting the domains a PAM service can auth against

Related ticket(s):

Problem statement

Some environments require that different PAM applications can use a different set of SSSD domains. The legacy PAM modules, such as pam_ldap were able to use a different configuration file altogether as a parameter for the PAM module. This wiki page describes a similar feature for the SSSD.

Use case

An example use-case is an environment that allows external users to authenticate to an FTP server. This server is running as a separate non-privileged user and should only be able to authenticate to a selected SSSD domain, separate from the internal company accounts. The administrator is able to leverage this new feature to mark allow the FTP user to only authenticate against one of the domains in the FTP PAM config file.

Overview of the solution

On the PAM client side, the PAM module should receive a new option that specifies the SSSD domains to authenticate against. However, the SSSD daemon can’t fully trust all PAM services. We can’t rely on the PAM service fields either, as the data the PAM client sends to the PAM application can be faked by the client, especially by users who posses shell access or can start custom applications. Instead, there needs to be a list of users who we trust. Typically, this would be a list of users who run the PAM aware applications we wish to restrict (such as vsftpd or openvpn). This list would default to root only.

These trusted users would be allowed to authenticate against any domain and would also be able to restrict the domains further using a new pam_sss option. For the untrusted users, we need to keep a list of domains allowed to authenticate against, too. Since by default there are no restrictions on the allowed domains, this list would default to “all domains are allowed”.

Implementation details

This section breaks down the Overview of the solution into consumable pieces.

Add a new option pam_trusted_users

A new option must be added to the PAM responder. This option will be a list of numerical UIDs or group names that are trusted or a special keyword “ALL”. This list will be parsed during PAM responder initialization (pam_process_init call) using the csv_string_to_uid_array function and stored in the PAM responder context (struct pam_ctx). The PAC responder does pretty much the same in the pac_process_init function.

In the responder, we already have the credentials of the client stored in the cli_ctx structure. When a new request comes into the pam_forwarder function, we will match the client UID against the list of trusted IDs and determine whether the client is trusted or not.

The default will be the special keyword ALL, meaning all users are trusted. This is in line with the current behaviour where any user can access any domain.

Add a option to limit the domains for untrusted users

Another option, called pam_allowed_auth_domains shall be added to the PAM responder. This option will list the SSSD domains an untrusted client can authenticate against. The option will accept either a comma-separated list of SSSD domains or any of two special values all and none. The default value will be none to make sure the administrator is required to spell out the domains that can be contacted by an untrusted client when he starts differentiating trusted and untrusted domains.

The option will be parsed during pam_process_init and stored in the pam_ctx structure. An untrusted client will only be allowed to send a request to a domain that matches the list of allowed domains.

In order to keep the implementation simple, the all keyword would copy all domain names into pam_ctx and the none keyword would set the variable holding the names to NULL. Then the check would be a simple loop for all cases.

Care must be taken to ensure a sensible PAM error code for cases where the domain wouldn’t match.

Add a new pam module option to limit the domains

The PAM module will gain a new option, called domains that will allow the administrator to use a list of domains to authenticate this PAM service against. In the PAM responder, this option will only be in effect for trusted clients. If the client is trusted, only domains listed in this PAM option will be considered for authentication.

Please note that a patch implementing most of the functionality of this PAM module option was contributed to the sssd-devel mailing list by Daniel Gollub already.

Password Changes

Password changes should be allowed against all domains, meaning that a user A (recognized via getpeercred) will be allow to perform a password change, i.e. implicitly allowed to access its own domain even if it is untrusted. Arbitrary password changes for other users should not be allowed.

Configuration Changes

Several new options, described in details in the previous section, will be introduced. No existing options will change defaults or gain new option values.

How To Test

  1. Prepare an SSSD installation with at least two domains A and B.
  2. Pick a PAM service that is running by a trusted user. One example might be VPN service ran by the openvpn user or similar. Add this user as a value of pam_trusted_users option in the [pam] section.
  3. Add one of the domains (domain A) as a domain= parameter into the auth section of your service’s PAM config file
  4. Authenticate using the selected PAM service as a user from domain A. The authentication should succeed.
  5. Authenticate using the same service as a user from domain B. The authentication should fail and there should be a reasonable (i.e. not System Error) return code returned to the application
  6. Authenticate using a different PAM service. Make sure this service is ran by an untrusted user (not root!). Logins against both A and B should fail.
  7. Set the value of pam_allowed_auth_domains to A. Login against A should succeed from a service running as untrusted user.
  8. Change the value of pam_allowed_auth_domains to all. Login against both domains should succeed from a service running as untrusted user.
  9. Remove the domains= option from the PAM config file. The trusted service should now be able to log in against both SSSD domains.
  10. Perform a password change as an untrusted user against a domain that he should not normally be allowed to use. The password change must succeed.