Fixes: https://fedorahosted.org/sssd/ticket/1021
Signed-off-by: Daniel Gollub dgollub@brocade.com Reviewed-by: Sven-Thorsten Dietrich sven@brocade.com --- src/providers/data_provider.h | 1 + src/responder/pam/pamsrv_cmd.c | 44 +++++++++++++++++++++++++++++++++++++++++- src/sss_client/pam_sss.c | 29 ++++++++++++++++++++++++++-- src/sss_client/sss_cli.h | 1 + 4 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index ebb4fad..0abfd0f 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -170,6 +170,7 @@ struct pam_data { char *tty; char *ruser; char *rhost; + char **requested_domains; struct sss_auth_token *authtok; struct sss_auth_token *newauthtok; uint32_t cli_pid; diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 140d541..c6539e5 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -44,6 +44,26 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
+static bool is_domain_requested(struct pam_data *pd, const char *domain_name) +{ + int i; + + /* If none specific domains got requested via pam, all domains are allowed. + * Which mimics the default/original behaviour. + */ + if (!pd->requested_domains) + return true; + + for (i = 0; pd->requested_domains[i]; i++) { + if (strcmp(domain_name, pd->requested_domains[i])) + continue; + + return true; + } + + return false; +} + static int extract_authtok_v2(struct sss_auth_token *tok, size_t data_size, uint8_t *body, size_t blen, size_t *c) @@ -146,6 +166,7 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, int ret; uint32_t start; uint32_t terminator; + char *requested_domains;
if (blen < 4*sizeof(uint32_t)+2) { DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n"); @@ -202,6 +223,16 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, ret = extract_string(&pd->rhost, size, body, blen, &c); if (ret != EOK) return ret; break; + case SSS_PAM_ITEM_REQUESTED_DOMAINS: + ret = extract_string(&requested_domains, size, body, blen, &c); + if (ret != EOK) return ret; + ret = split_on_separator(pd, requested_domains, ',', true, true, + &pd->requested_domains, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to parse requested_domains list!\n")); + return ret; + } + break; case SSS_PAM_ITEM_CLI_PID: ret = extract_uint32_t(&pd->cli_pid, size, body, blen, &c); @@ -836,12 +867,22 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) ret = ENOENT; goto done; } + + /* skip this domain if not requested */ + if (!is_domain_requested(pd, dom->name)) { + ret = ENOENT; + goto done; + } } else { for (dom = preq->cctx->rctx->domains; dom; dom = get_next_domain(dom, false)) { if (dom->fqnames) continue;
+ /* skip this domain if not requested */ + if (!is_domain_requested(pd, dom->name)) + continue; + ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout, dom, pd->user); if (ncret == ENOENT) { @@ -856,7 +897,8 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) "User [%s@%s] filtered out (negative cache). " "Trying next domain.\n", pd->user, dom->name); } - if (!dom) { + + if (!dom || !is_domain_requested(pd, dom->name)) { ret = ENOENT; goto done; } diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index d2502d1..4d76bd2 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -58,6 +58,7 @@ #define PW_RESET_MSG_MAX_SIZE 4096
#define OPT_RETRY_KEY "retry=" +#define OPT_DOMAINS_KEY "domains="
struct pam_items { const char* pam_service; @@ -81,6 +82,8 @@ struct pam_items { pid_t cli_pid; const char *login_name; char *domain_name; + const char *requested_domains; + size_t requested_domains_size; };
#define DEBUG_MGS_LEN 1024 @@ -246,6 +249,9 @@ static int pack_message_v3(struct pam_items *pi, size_t *size, len += pi->pam_newauthtok != NULL ? 3*sizeof(uint32_t) + pi->pam_newauthtok_size : 0; len += 3*sizeof(uint32_t); /* cli_pid */ + len += *pi->requested_domains != '\0' ? + 2*sizeof(uint32_t) + pi->requested_domains_size : 0; +
buf = malloc(len); if (buf == NULL) { @@ -271,6 +277,9 @@ static int pack_message_v3(struct pam_items *pi, size_t *size, rp += add_string_item(SSS_PAM_ITEM_RHOST, pi->pam_rhost, pi->pam_rhost_size, &buf[rp]);
+ rp += add_string_item(SSS_PAM_ITEM_REQUESTED_DOMAINS, pi->requested_domains, pi->requested_domains_size, + &buf[rp]); + rp += add_uint32_t_item(SSS_PAM_ITEM_CLI_PID, (uint32_t) pi->cli_pid, &buf[rp]);
@@ -1061,6 +1070,9 @@ static int get_pam_items(pam_handle_t *pamh, struct pam_items *pi)
pi->domain_name = NULL;
+ if (pi->requested_domains == NULL) pi->requested_domains=""; + pi->requested_domains_size=strlen(pi->requested_domains)+1; + return PAM_SUCCESS; }
@@ -1080,6 +1092,7 @@ static void print_pam_items(struct pam_items *pi) D(("Authtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_authtok))); D(("Newauthtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_newauthtok))); D(("Cli_PID: %d", pi->cli_pid)); + D(("Requested domains: %s", pi->requested_domains)); }
static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi, @@ -1271,7 +1284,8 @@ static int prompt_new_password(pam_handle_t *pamh, struct pam_items *pi) }
static void eval_argv(pam_handle_t *pamh, int argc, const char **argv, - uint32_t *flags, int *retries, bool *quiet_mode) + uint32_t *flags, int *retries, bool *quiet_mode, + const char **domains) { char *ep;
@@ -1284,6 +1298,14 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv, *flags |= FLAGS_USE_FIRST_PASS; } else if (strcmp(*argv, "use_authtok") == 0) { *flags |= FLAGS_USE_AUTHTOK; + } else if (strncmp(*argv, OPT_DOMAINS_KEY, strlen(OPT_DOMAINS_KEY)) == 0) { + if (*(*argv+strlen(OPT_DOMAINS_KEY)) == '\0') { + logger(pamh, LOG_ERR, "Missing argument to option domains."); + *domains = '\0'; + } else { + *domains = *argv+strlen(OPT_DOMAINS_KEY); + } + } else if (strncmp(*argv, OPT_RETRY_KEY, strlen(OPT_RETRY_KEY)) == 0) { if (*(*argv+6) == '\0') { logger(pamh, LOG_ERR, "Missing argument to option retry."); @@ -1443,12 +1465,15 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh, bool retry = false; bool quiet_mode = false; int retries = 0; + const char *domains = NULL;
bindtextdomain(PACKAGE, LOCALEDIR);
D(("Hello pam_sssd: %d", task));
- eval_argv(pamh, argc, argv, &flags, &retries, &quiet_mode); + eval_argv(pamh, argc, argv, &flags, &retries, &quiet_mode, &domains); + + pi.requested_domains = domains;
ret = get_pam_items(pamh, &pi); if (ret != PAM_SUCCESS) { diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h index 16a08e1..15f8322 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -314,6 +314,7 @@ enum pam_item_type { SSS_PAM_ITEM_NEWAUTHTOK, SSS_PAM_ITEM_CLI_LOCALE, SSS_PAM_ITEM_CLI_PID, + SSS_PAM_ITEM_REQUESTED_DOMAINS, };
#define SSS_NSS_MAX_ENTRIES 256
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain - "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
I guess this should solve what Mark commented in the ticket to do by running two SSH daemons with different authentication domains as well. I also agree what he is saying, that users will first look for pam options ... this was the first think I did as well.
Thanks! Daniel
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain
- "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
On Wed, 30 Jul 2014 01:58:00 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain
- "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
But this would require restart of sssd each time one would add a new (e.g.) VPN endpoint - right? Right now it is quite convinced that one just can change the /etc/pam.d/* configuration without requiring to restart/reload the PAM-enabled service (e.g. VPN daemon) which authenticates against pam_sss. And also not requiring to restart sssd during business hours or so.
There is no "reload" configuration functionality in sssd yet - right?
On Wed, Jul 30, 2014 at 11:07:01AM +0200, Daniel Gollub wrote:
But this would require restart of sssd each time one would add a new (e.g.) VPN endpoint - right?
Right, is that something you would do regularly, though and not a one-off thing when you set up your infrastructure.
Right now it is quite convinced that one just can change the /etc/pam.d/* configuration without requiring to restart/reload the PAM-enabled service (e.g. VPN daemon) which authenticates against pam_sss. And also not requiring to restart sssd during business hours or so.
There is no "reload" configuration functionality in sssd yet - right?
Correct, we tried and failed, reloading configuration on the fly is much harder to implement correctly than it seems.
On Wed, 30 Jul 2014 02:17:59 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 30, 2014 at 11:07:01AM +0200, Daniel Gollub wrote:
But this would require restart of sssd each time one would add a new (e.g.) VPN endpoint - right?
Right, is that something you would do regularly, though and not a one-off thing when you set up your infrastructure.
In my use-case, using that for a router/vpn appliance this might could happen more often - but not regularly. E.g. adding new region LDAP for a VPN or something like that - or dropping VPN access to a specific VPN concentrate or so. The neat thing would be that one could add an additional e.g. LDAP or AD server for authentication - without the need to worry about temporarily failing authentication of clients while SSSD is restarting.
Is the enumeration via LDAP/AD is done on every start-up of SSSD? (Even if this is not recommended on very large LDAP trees - regular enumeration could be prevent and avoid some noise at somer other end)
Right now it is quite convinced that one just can change the /etc/pam.d/* configuration without requiring to restart/reload the PAM-enabled service (e.g. VPN daemon) which authenticates against pam_sss. And also not requiring to restart sssd during business hours or so.
There is no "reload" configuration functionality in sssd yet - right?
Correct, we tried and failed, reloading configuration on the fly is much harder to implement correctly than it seems.
Yeah, I could imagine that is not trivial to do. So ideal I would like to avoid to restart sssd every time someone tries to fine-tune the correct authentication setting for one new VPN endpoint - by potentially disturbing authentication of "live"/"production" used VPN endpoints on the system.
On Wed, 2014-07-30 at 10:58 +0200, Jakub Hrozek wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain
- "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
How do you trust what is claimed by a client ? Is this list a filter or is it meant as an access control to avoid divulging other domains information to specific processes ?
Simo.
On Wed, 30 Jul 2014 03:59:48 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 10:58 +0200, Jakub Hrozek wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain
- "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
How do you trust what is claimed by a client ?
By client you mean a pam-client/-application - right?
Isn't trusting /etc/pam.d/<service_name> file safe enough? Do you see here any specific attack vector / security risk? (By service_name is meant what the client application is providing to pam_start(3))
Is this list a filter or is it meant as an access control to avoid divulging other domains information to specific processes ?
This is primarily meant as "access filter" for authentication - not quite sure but maybe the later one is meant by this.
The idea is that a pam-client gets configured to a specific PAM service, which consists of pam_sss.so domains=ldap.example.com and only allows authentication against this ldap.example.com SSSD domain.
This is not targeted that any other process/client on the same system as SSSD is running, is restricted/avoided to retrieve information from any other SSSD domains. If some non-root user wants to retrieves via NSS information from emea.example.com ... even if this user got logged in via SSH and authenticated against pam_sss.so domains=emea.examples.com. This user will not be prevent to retrieve information from domains=id.example.com via NSS or so.
-Daniel
On Wed, 2014-07-30 at 16:23 +0200, Daniel Gollub wrote:
On Wed, 30 Jul 2014 03:59:48 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 10:58 +0200, Jakub Hrozek wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain
- "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
How do you trust what is claimed by a client ?
By client you mean a pam-client/-application - right?
Isn't trusting /etc/pam.d/<service_name> file safe enough? Do you see here any specific attack vector / security risk? (By service_name is meant what the client application is providing to pam_start(3))
Pam can be run by any user, so anything can be faked, unless we force to accept only connections from the root user.
Is this list a filter or is it meant as an access control to avoid divulging other domains information to specific processes ?
This is primarily meant as "access filter" for authentication - not quite sure but maybe the later one is meant by this.
The idea is that a pam-client gets configured to a specific PAM service, which consists of pam_sss.so domains=ldap.example.com and only allows authentication against this ldap.example.com SSSD domain.
This is not targeted that any other process/client on the same system as SSSD is running, is restricted/avoided to retrieve information from any other SSSD domains. If some non-root user wants to retrieves via NSS information from emea.example.com ... even if this user got logged in via SSH and authenticated against pam_sss.so domains=emea.examples.com. This user will not be prevent to retrieve information from domains=id.example.com via NSS or so.
The questions is: is this mechanism intended to prevent authentication attempts against other domains ? Or is it merely a way to avoid mistakes but not a security measure ?
Simo.
On Wed, 30 Jul 2014 08:46:36 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 16:23 +0200, Daniel Gollub wrote:
On Wed, 30 Jul 2014 03:59:48 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 10:58 +0200, Jakub Hrozek wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote: > Fixes: > https://fedorahosted.org/sssd/ticket/1021
Thanks a lot for the patch!
I wonder, though if you read the discussion in the ticket where Simo and Sumit argued this functionality should be implemented in sssd.conf rather than the pam module?
If you saw the discussion, what prompted you to continue the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain
- "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
How do you trust what is claimed by a client ?
By client you mean a pam-client/-application - right?
Isn't trusting /etc/pam.d/<service_name> file safe enough? Do you see here any specific attack vector / security risk? (By service_name is meant what the client application is providing to pam_start(3))
Pam can be run by any user, so anything can be faked, unless we force to accept only connections from the root user.
What could the non-root user fake here so it becomes a security with the introduction of this additional parameter?
Having a different pam configuration with different pam_sss.so parameter? What are the security implication with that and the introduction of the domains= parameter?
Could you give a example?
Is this list a filter or is it meant as an access control to avoid divulging other domains information to specific processes ?
This is primarily meant as "access filter" for authentication - not quite sure but maybe the later one is meant by this.
The idea is that a pam-client gets configured to a specific PAM service, which consists of pam_sss.so domains=ldap.example.com and only allows authentication against this ldap.example.com SSSD domain.
This is not targeted that any other process/client on the same system as SSSD is running, is restricted/avoided to retrieve information from any other SSSD domains. If some non-root user wants to retrieves via NSS information from emea.example.com ... even if this user got logged in via SSH and authenticated against pam_sss.so domains=emea.examples.com. This user will not be prevent to retrieve information from domains=id.example.com via NSS or so.
The questions is: is this mechanism intended to prevent authentication attempts against other domains ?
Yes.
If pam_sss.so domains=emea.examples.com is set only this sssd domain should be used for authentication - not any other domain.
VPN-endpoint example: OpenVPN is configured to use /etc/pam.d/it-dep for authentication (via auth-pam plugin). it-dep file consists of: "{auth,account} required pam_sss.so domains=it.example.com"
User "alice" exists in the emea.examples.com domain, but not in the it.example.com domain. User "bob" exists in "it.example.com".
Expected behavior:
User "bob" is able to authenticate on that particular OpenVPN instance which is configured to use PAM service "it-dep". User "alice" authentication via OpenVPN would fail, since there is no user in the "it.example.com" domain, and no further domains get queried for authentication by pam_sss.so
A second OpenVPN instance on the same system could be configured with a different PAM service "emea":
"{auth,account required pam_sss.so domains=emea.example.com,it.example.com"
... which would only grant access for "alice" and for "bob".
Do you see here any potential way to fake and break something?
I guess there are other scenarios, especially if those provide shell access to that system. Obviously I do not want to introduce something which could break any other usage scenarios - security wise.
If I would run the same example with multiple SSH daemons and grant access to "alice" and "bob" via two different sssd domains which have two different PAM services configured which authenticate explicitly against dedicated sssd domains ... how could non-root users fake something and gain privileges?
Or is it merely a way to avoid mistakes but not a security measure ?
No.
Thanks! Daniel
On Wed, 2014-07-30 at 18:29 +0200, Daniel Gollub wrote:
On Wed, 30 Jul 2014 08:46:36 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 16:23 +0200, Daniel Gollub wrote:
On Wed, 30 Jul 2014 03:59:48 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 10:58 +0200, Jakub Hrozek wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
Hi Jakub,
On Tue, 29 Jul 2014 07:32:58 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
> On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub > wrote: > > Fixes: > > https://fedorahosted.org/sssd/ticket/1021 > > Thanks a lot for the patch! > > I wonder, though if you read the discussion in the ticket > where Simo and Sumit argued this functionality should be > implemented in sssd.conf rather than the pam module? > > If you saw the discussion, what prompted you to continue > the pam option way?
What I plan to do is following:
Have a sssd.conf with multiple domains configured of different types and configuration configured - e.g.
- "emea.example.com", "hq.example.com" both as LDAP domain
- "it.example.com" as Local-domain
With that I want to enable PAM-aware services to use pam_sss to authenticate not against all but against expliclty selected combination. By creating multiple pam configuration/service for multiple e.g. VPN endpoints on the same host. Counting on that example:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
And a completely different service / e.g. Webserver which should grant access for all SSSD domains: /etc/pam.d/random-intranet.conf
Which consists of: {auth,account} ... pam_sss.so
And so on ... everything on the same machine.
This VPN service (e.g. OpenVPN) requires no modification to support this. For each of those PAM configuration another OpenVPN daemon gets started with a different PAM plugin configuration (and different routing options and such).
I am not quite sure how this could be done by moving the domains= configuration inside sssd.conf, without modifying the existing PAM-aware services - like OpenSSH, OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
How do you trust what is claimed by a client ?
By client you mean a pam-client/-application - right?
Isn't trusting /etc/pam.d/<service_name> file safe enough? Do you see here any specific attack vector / security risk? (By service_name is meant what the client application is providing to pam_start(3))
Pam can be run by any user, so anything can be faked, unless we force to accept only connections from the root user.
What could the non-root user fake here so it becomes a security with the introduction of this additional parameter?
Having a different pam configuration with different pam_sss.so parameter? What are the security implication with that and the introduction of the domains= parameter?
Could you give a example?
Is this list a filter or is it meant as an access control to avoid divulging other domains information to specific processes ?
This is primarily meant as "access filter" for authentication - not quite sure but maybe the later one is meant by this.
The idea is that a pam-client gets configured to a specific PAM service, which consists of pam_sss.so domains=ldap.example.com and only allows authentication against this ldap.example.com SSSD domain.
This is not targeted that any other process/client on the same system as SSSD is running, is restricted/avoided to retrieve information from any other SSSD domains. If some non-root user wants to retrieves via NSS information from emea.example.com ... even if this user got logged in via SSH and authenticated against pam_sss.so domains=emea.examples.com. This user will not be prevent to retrieve information from domains=id.example.com via NSS or so.
The questions is: is this mechanism intended to prevent authentication attempts against other domains ?
Yes.
Ok, then you cannot use a client provided access list.
If pam_sss.so domains=emea.examples.com is set only this sssd domain should be used for authentication - not any other domain.
VPN-endpoint example: OpenVPN is configured to use /etc/pam.d/it-dep for authentication (via auth-pam plugin). it-dep file consists of: "{auth,account} required pam_sss.so domains=it.example.com"
User "alice" exists in the emea.examples.com domain, but not in the it.example.com domain. User "bob" exists in "it.example.com".
Expected behavior:
User "bob" is able to authenticate on that particular OpenVPN instance which is configured to use PAM service "it-dep". User "alice" authentication via OpenVPN would fail, since there is no user in the "it.example.com" domain, and no further domains get queried for authentication by pam_sss.so
A second OpenVPN instance on the same system could be configured with a different PAM service "emea":
"{auth,account required pam_sss.so domains=emea.example.com,it.example.com"
... which would only grant access for "alice" and for "bob".
Do you see here any potential way to fake and break something?
Not for the OpenVPN case, where you control the client so you can use whatever configuration you want.
I guess there are other scenarios, especially if those provide shell access to that system.
These are the scenarios I care about, or in general a scenario where a service can be compromised and then a privilege escalation attack can be attempted via password guessing.
Obviously I do not want to introduce something which could break any other usage scenarios - security wise.
This is what I am concerned about, not your specific use case, where you control both sides so you can trust them both.
If I would run the same example with multiple SSH daemons and grant access to "alice" and "bob" via two different sssd domains which have two different PAM services configured which authenticate explicitly against dedicated sssd domains ... how could non-root users fake something and gain privileges?
They wouldn't, and the sshd server is the same case as an openvpn server which is not my concern. My concern is user processes connecting to sssd_pam, if you want to confine which processes can access, then the configuration needs to be on the server side and the server needs to check who is the caller.
Or is it merely a way to avoid mistakes but not a security measure ?
No.
To be honest, in the openvpn -> sssd case this is what it is, as the openvpn process collaborates with sssd to define the security boundaries of what domain should be used.
Don't think about my questions with your narrow use case in mind, they are directed at a system where random user processes can be run, like on a multiseat system.
Simo.
On Wed, 30 Jul 2014 10:19:48 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 18:29 +0200, Daniel Gollub wrote:
On Wed, 30 Jul 2014 08:46:36 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 16:23 +0200, Daniel Gollub wrote:
On Wed, 30 Jul 2014 03:59:48 -0700 Simo Sorce ssorce@redhat.com wrote:
On Wed, 2014-07-30 at 10:58 +0200, Jakub Hrozek wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote: > Hi Jakub, > > On Tue, 29 Jul 2014 07:32:58 -0700 > Jakub Hrozek jhrozek@redhat.com wrote: > > > On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub > > wrote: > > > Fixes: > > > https://fedorahosted.org/sssd/ticket/1021 > > > > Thanks a lot for the patch! > > > > I wonder, though if you read the discussion in the > > ticket where Simo and Sumit argued this functionality > > should be implemented in sssd.conf rather than the pam > > module? > > > > If you saw the discussion, what prompted you to continue > > the pam option way? > > What I plan to do is following: > > Have a sssd.conf with multiple domains configured of > different types and configuration configured - e.g. > > - "emea.example.com", "hq.example.com" both as LDAP > domain > - "it.example.com" as Local-domain > > With that I want to enable PAM-aware services to use > pam_sss to authenticate not against all but against > expliclty selected combination. By creating multiple pam > configuration/service for multiple e.g. VPN endpoints on > the same host. Counting on that example: > > VPN service #1 is configured to use PAM > configuration/service: /etc/pam.d/vpn-sales-dep.conf > > Which consists of: > {auth,account} ... pam_sss.so > domains=emea.example.com,hq.example.com > > VPN service #2 is ocnfigued to use PAM > configuration/service: /etc/pam.d/vpn-it.conf > > Which consists of: > {auth,account} ... pam_sss.so domains=it.example.com > > And a completely different service / e.g. Webserver which > should grant access for all SSSD domains: > /etc/pam.d/random-intranet.conf > > Which consists of: > {auth,account} ... pam_sss.so > > > > And so on ... everything on the same machine. > > This VPN service (e.g. OpenVPN) requires no modification > to support this. For each of those PAM configuration > another OpenVPN daemon gets started with a different PAM > plugin configuration (and different routing options and > such). > > > I am not quite sure how this could be done by moving the > domains= configuration inside sssd.conf, without modifying > the existing PAM-aware services - like OpenSSH, > OpenVPN, ...
My understanding was that the domain section would grow a new parameter, something like allowed_pam_services. Then in your case you would have:
[domain/emea.example.com] allowed_pam_services = vpn-sales-dep
[domain/hq.example.com] allowed_pam_services = vpn-sales-dep
[domain/it.example.com] allowed_pam_services = vpn-it
I see the point that your configuration is more flexible, though.
However, we had some discussion around this effort internally with Jan and Simo couple of weeks ago. I added them to the CC list so they can check of your approach would work for them..
How do you trust what is claimed by a client ?
By client you mean a pam-client/-application - right?
Isn't trusting /etc/pam.d/<service_name> file safe enough? Do you see here any specific attack vector / security risk? (By service_name is meant what the client application is providing to pam_start(3))
Pam can be run by any user, so anything can be faked, unless we force to accept only connections from the root user.
What could the non-root user fake here so it becomes a security with the introduction of this additional parameter?
Having a different pam configuration with different pam_sss.so parameter? What are the security implication with that and the introduction of the domains= parameter?
Could you give a example?
Is this list a filter or is it meant as an access control to avoid divulging other domains information to specific processes ?
This is primarily meant as "access filter" for authentication - not quite sure but maybe the later one is meant by this.
The idea is that a pam-client gets configured to a specific PAM service, which consists of pam_sss.so domains=ldap.example.com and only allows authentication against this ldap.example.com SSSD domain.
This is not targeted that any other process/client on the same system as SSSD is running, is restricted/avoided to retrieve information from any other SSSD domains. If some non-root user wants to retrieves via NSS information from emea.example.com ... even if this user got logged in via SSH and authenticated against pam_sss.so domains=emea.examples.com. This user will not be prevent to retrieve information from domains=id.example.com via NSS or so.
The questions is: is this mechanism intended to prevent authentication attempts against other domains ?
Yes.
Ok, then you cannot use a client provided access list.
If pam_sss.so domains=emea.examples.com is set only this sssd domain should be used for authentication - not any other domain.
VPN-endpoint example: OpenVPN is configured to use /etc/pam.d/it-dep for authentication (via auth-pam plugin). it-dep file consists of: "{auth,account} required pam_sss.so domains=it.example.com"
User "alice" exists in the emea.examples.com domain, but not in the it.example.com domain. User "bob" exists in "it.example.com".
Expected behavior:
User "bob" is able to authenticate on that particular OpenVPN instance which is configured to use PAM service "it-dep". User "alice" authentication via OpenVPN would fail, since there is no user in the "it.example.com" domain, and no further domains get queried for authentication by pam_sss.so
A second OpenVPN instance on the same system could be configured with a different PAM service "emea":
"{auth,account required pam_sss.so domains=emea.example.com,it.example.com"
... which would only grant access for "alice" and for "bob".
Do you see here any potential way to fake and break something?
Not for the OpenVPN case, where you control the client so you can use whatever configuration you want.
I guess there are other scenarios, especially if those provide shell access to that system.
These are the scenarios I care about, or in general a scenario where a service can be compromised and then a privilege escalation attack can be attempted via password guessing.
Ok, now I see what you were thinking of ...
So this kind of issue did not exist before - since the pam module was not controlling access boundaries. Current sssd would not be affected by privilege escalation attack via password guessing - since there was not intention/functionality to limit the authentication for specific users to certain domains. Since users would authenticate anyway against all available domains today - and there was no intention so far to prevent hat on PAM level. (Exception: enforcing domain name in the authentication username)
With the domains= parameter introduction sssd users could thing that the domain separation would be strict - and could avoid that someone performs authentication against other domains. But this is obviously not the case when regular users have shell access on the system were sssd is running .. since someone could perform PAM authentication against another PAM service file, instead of the designated one - which is limited only to certain domains.
Obviously I do not want to introduce something which could break any other usage scenarios - security wise.
This is what I am concerned about, not your specific use case, where you control both sides so you can trust them both.
If I would run the same example with multiple SSH daemons and grant access to "alice" and "bob" via two different sssd domains which have two different PAM services configured which authenticate explicitly against dedicated sssd domains ... how could non-root users fake something and gain privileges?
They wouldn't, and the sshd server is the same case as an openvpn server which is not my concern. My concern is user processes connecting to sssd_pam, if you want to confine which processes can access, then the configuration needs to be on the server side and the server needs to check who is the caller.
In case of the SSH scenario ... this could end up having in granting shell access - if intended. And then user processes could connect to sssd_pam and try the same privileges escalation by password guessing. But yeah, I got your idea.
So what would be your suggestion to solve that? Ideally I would like to keep the flexibility I have with that implementation and would like to avoid sssd restart/small-outages when access for specific pam-clients gets modified/added.
What do you think about a generic parameter for the pam section:
[pam] trust_all_pam_clients = <[false]|true>
Which is "false" by default, and should be only set if the target system can guarantee that no untrusted users can connect to sssd_pam? (e.g. systems with no shell access to "untrusted" users)
Or by configuring which users are trusted as PAM client, where it is safe to interpret the domains= parameter?
[pam] trusted_pam_clients = root, openvpn, strongswan, ...
(Haven't checked how hard it is to actually determine on a safe why how the callee is ... or is there already something in place in the pam responder or so?)
We could also introduce:
[domain it.example.com] pam_services = it-dep, ...
But here we would loose flexibility, when new (e.g. VPN-) service instances get spawned with their individual PAM service configuration - which would require then each time a sssd restart - due to configuration change.
Or is it merely a way to avoid mistakes but not a security measure ?
No.
To be honest, in the openvpn -> sssd case this is what it is, as the openvpn process collaborates with sssd to define the security boundaries of what domain should be used.
It depends on the perspective ... for the PAM client - some service like OpenVPN - it can be seen as security measure. By only allowing certain users to authenticate for a particular service.
From the sssd perspective this is different ... since the entire control would be on the client side - which should not be trusted in all scenarios.
Don't think about my questions with your narrow use case in mind, they are directed at a system where random user processes can be run, like on a multiseat system.
Ok.
Thanks! Daniel
On Thu, 2014-07-31 at 13:27 +0200, Daniel Gollub wrote:
What do you think about a generic parameter for the pam section:
[pam] trust_all_pam_clients = <[false]|true>
Which is "false" by default, and should be only set if the target system can guarantee that no untrusted users can connect to sssd_pam? (e.g. systems with no shell access to "untrusted" users)
Or by configuring which users are trusted as PAM client, where it is safe to interpret the domains= parameter?
[pam] trusted_pam_clients = root, openvpn, strongswan, ...
It should be: trusted_pam_users = root, openvpn, ...
Defaults to root only
(Haven't checked how hard it is to actually determine on a safe why how the callee is ... or is there already something in place in the pam responder or so?)
We could also introduce:
[domain it.example.com] pam_services = it-dep, ...
But here we would loose flexibility, when new (e.g. VPN-) service instances get spawned with their individual PAM service configuration - which would require then each time a sssd restart - due to configuration change.
No, this is useless as the pam service is sent by the client, so it cannot be trusted on its own.
Or is it merely a way to avoid mistakes but not a security measure ?
No.
To be honest, in the openvpn -> sssd case this is what it is, as the openvpn process collaborates with sssd to define the security boundaries of what domain should be used.
It depends on the perspective ... for the PAM client - some service like OpenVPN - it can be seen as security measure. By only allowing certain users to authenticate for a particular service.
From the sssd perspective this is different ... since the entire control would be on the client side - which should not be trusted in all scenarios.
Don't think about my questions with your narrow use case in mind, they are directed at a system where random user processes can be run, like on a multiseat system.
Ok.
So the trusted_pam_users should be allowed to auth against any domain and be trusted to limit themselves via the domains parameter.
All other users should be confined to a list of configured domains, by default that may be none or all, depending on which configuration we think is more reasonable in a standard system, right now we do not limit anything so we could say "all" is the default and admin need to explicitly change it to none when they want to apply limitations.
So something like: allowed_pam_auth_domains = all|none|[comma separate domain names] Default: all
Password changes should still be allowed in any case so when a user connect it's domain need to be retrieved and access to auth to that domain (at least for the "self") need to be allowed.
Simo.
On Thu, Jul 31, 2014 at 08:04:01AM -0400, Simo Sorce wrote:
On Thu, 2014-07-31 at 13:27 +0200, Daniel Gollub wrote:
What do you think about a generic parameter for the pam section:
[pam] trust_all_pam_clients = <[false]|true>
Which is "false" by default, and should be only set if the target system can guarantee that no untrusted users can connect to sssd_pam? (e.g. systems with no shell access to "untrusted" users)
Or by configuring which users are trusted as PAM client, where it is safe to interpret the domains= parameter?
[pam] trusted_pam_clients = root, openvpn, strongswan, ...
It should be: trusted_pam_users = root, openvpn, ...
Defaults to root only
(Haven't checked how hard it is to actually determine on a safe why how the callee is ... or is there already something in place in the pam responder or so?)
We could also introduce:
[domain it.example.com] pam_services = it-dep, ...
But here we would loose flexibility, when new (e.g. VPN-) service instances get spawned with their individual PAM service configuration - which would require then each time a sssd restart - due to configuration change.
No, this is useless as the pam service is sent by the client, so it cannot be trusted on its own.
Or is it merely a way to avoid mistakes but not a security measure ?
No.
To be honest, in the openvpn -> sssd case this is what it is, as the openvpn process collaborates with sssd to define the security boundaries of what domain should be used.
It depends on the perspective ... for the PAM client - some service like OpenVPN - it can be seen as security measure. By only allowing certain users to authenticate for a particular service.
From the sssd perspective this is different ... since the entire control would be on the client side - which should not be trusted in all scenarios.
Don't think about my questions with your narrow use case in mind, they are directed at a system where random user processes can be run, like on a multiseat system.
Ok.
So the trusted_pam_users should be allowed to auth against any domain and be trusted to limit themselves via the domains parameter.
All other users should be confined to a list of configured domains, by default that may be none or all, depending on which configuration we think is more reasonable in a standard system, right now we do not limit anything so we could say "all" is the default and admin need to explicitly change it to none when they want to apply limitations.
So something like: allowed_pam_auth_domains = all|none|[comma separate domain names] Default: all
Password changes should still be allowed in any case so when a user connect it's domain need to be retrieved and access to auth to that domain (at least for the "self") need to be allowed.
Simo.
Thank you for the writeup Simo!
Sorry everyone about the delay. I'm resurrecting this thread now that some RHEL deadlines are finally over and we can get back to upstream development.
Daniel, thank you again for the initial implementation. Are you interested in working with us on implementing what Simo proposed? Maybe we can turn his design into a design page so that it's clear what needs to be implemented?
If not, that's fine, we can do the work ourselves, but if you're interested in collaborating with us on the work, please let me know :-)
On Wed, 17 Sep 2014 05:25:51 -0700 Jakub Hrozek jhrozek@redhat.com wrote:
On Thu, Jul 31, 2014 at 08:04:01AM -0400, Simo Sorce wrote:
On Thu, 2014-07-31 at 13:27 +0200, Daniel Gollub wrote:
What do you think about a generic parameter for the pam section:
[pam] trust_all_pam_clients = <[false]|true>
Which is "false" by default, and should be only set if the target system can guarantee that no untrusted users can connect to sssd_pam? (e.g. systems with no shell access to "untrusted" users)
Or by configuring which users are trusted as PAM client, where it is safe to interpret the domains= parameter?
[pam] trusted_pam_clients = root, openvpn, strongswan, ...
It should be: trusted_pam_users = root, openvpn, ...
Defaults to root only
(Haven't checked how hard it is to actually determine on a safe why how the callee is ... or is there already something in place in the pam responder or so?)
We could also introduce:
[domain it.example.com] pam_services = it-dep, ...
But here we would loose flexibility, when new (e.g. VPN-) service instances get spawned with their individual PAM service configuration - which would require then each time a sssd restart
- due to configuration change.
No, this is useless as the pam service is sent by the client, so it cannot be trusted on its own.
Or is it merely a way to avoid mistakes but not a security measure ?
No.
To be honest, in the openvpn -> sssd case this is what it is, as the openvpn process collaborates with sssd to define the security boundaries of what domain should be used.
It depends on the perspective ... for the PAM client - some service like OpenVPN - it can be seen as security measure. By only allowing certain users to authenticate for a particular service.
From the sssd perspective this is different ... since the entire control would be on the client side - which should not be trusted in all scenarios.
Don't think about my questions with your narrow use case in mind, they are directed at a system where random user processes can be run, like on a multiseat system.
Ok.
So the trusted_pam_users should be allowed to auth against any domain and be trusted to limit themselves via the domains parameter.
All other users should be confined to a list of configured domains, by default that may be none or all, depending on which configuration we think is more reasonable in a standard system, right now we do not limit anything so we could say "all" is the default and admin need to explicitly change it to none when they want to apply limitations.
So something like: allowed_pam_auth_domains = all|none|[comma separate domain names] Default: all
Password changes should still be allowed in any case so when a user connect it's domain need to be retrieved and access to auth to that domain (at least for the "self") need to be allowed.
Simo.
Thank you for the writeup Simo!
Sorry everyone about the delay. I'm resurrecting this thread now that some RHEL deadlines are finally over and we can get back to upstream development.
Daniel, thank you again for the initial implementation. Are you interested in working with us on implementing what Simo proposed? Maybe we can turn his design into a design page so that it's clear what needs to be implemented?
Sure, I can do that. I'm busy this week with some other stuff. But next week I hope I can provide you an updated patch which introduces the allowed_pam_auth_domains parameter.
If not, that's fine, we can do the work ourselves, but if you're interested in collaborating with us on the work, please let me know :-)
-Daniel
On Wed, Sep 17, 2014 at 05:15:50PM +0200, Daniel Gollub wrote:
Thank you for the writeup Simo!
Sorry everyone about the delay. I'm resurrecting this thread now that some RHEL deadlines are finally over and we can get back to upstream development.
Daniel, thank you again for the initial implementation. Are you interested in working with us on implementing what Simo proposed? Maybe we can turn his design into a design page so that it's clear what needs to be implemented?
Sure, I can do that. I'm busy this week with some other stuff. But next week I hope I can provide you an updated patch which introduces the allowed_pam_auth_domains parameter.
Ah, great, thank you very much. In that case, I will make sure all the info is on a design page and all developers "Sign it off" before you start with the implementation.
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
When the client using the PAM services vpn-sales-dep will want to authenticate the user, will it be expected to call pam_start with "login" or "login@emea.example.com"?
On Sat, 2 Aug 2014 12:15:01 -0700 Jan Pazdziora jpazdziora@redhat.com wrote:
On Tue, Jul 29, 2014 at 04:59:23PM +0200, Daniel Gollub wrote:
VPN service #1 is configured to use PAM configuration/service: /etc/pam.d/vpn-sales-dep.conf
Which consists of: {auth,account} ... pam_sss.so domains=emea.example.com,hq.example.com
VPN service #2 is ocnfigued to use PAM configuration/service: /etc/pam.d/vpn-it.conf
Which consists of: {auth,account} ... pam_sss.so domains=it.example.com
When the client using the PAM services vpn-sales-dep will want to authenticate the user, will it be expected to call pam_start with "login" or "login@emea.example.com"?
This proposed patch is not changing the existing sssd/pam_sss behavior if a domain in login is required or not. If the sssd option "use_fully_qualified_names" is false (default) then both will work. If set to true, the domain needs to be specified.
If the PAM service is using domains=emea.example,hq.example.com and someone tries to sneak in by authenticating with: login@it.example.com ... this will not work. The sssd pam responder code - with this patch applied - is intended to completely skip any other domain which is not set by the domains= argument.
On Sun, Aug 03, 2014 at 10:08:03AM +0200, Daniel Gollub wrote:
This proposed patch is not changing the existing sssd/pam_sss behavior if a domain in login is required or not. If the sssd option "use_fully_qualified_names" is false (default) then both will work. If set to true, the domain needs to be specified.
If the PAM service is using domains=emea.example,hq.example.com and someone tries to sneak in by authenticating with: login@it.example.com ... this will not work. The sssd pam responder code - with this patch applied - is intended to completely skip any other domain which is not set by the domains= argument.
My concern is this -- if we are going to harden the list of domains that will be used for authentication (or identity operations), it would be good to find a way to also make it possible for the application using the PAM stack to find out which domain (and thus which identity) sssd actually used. So for "login", was it "login@emea.example.com" or "login@hq.example.com" that was used?
Do we have a way to return the information to the application?
On Sun, 3 Aug 2014 01:28:11 -0700 Jan Pazdziora jpazdziora@redhat.com wrote:
On Sun, Aug 03, 2014 at 10:08:03AM +0200, Daniel Gollub wrote:
This proposed patch is not changing the existing sssd/pam_sss behavior if a domain in login is required or not. If the sssd option "use_fully_qualified_names" is false (default) then both will work. If set to true, the domain needs to be specified.
If the PAM service is using domains=emea.example,hq.example.com and someone tries to sneak in by authenticating with: login@it.example.com ... this will not work. The sssd pam responder code - with this patch applied - is intended to completely skip any other domain which is not set by the domains= argument.
My concern is this -- if we are going to harden the list of domains that will be used for authentication (or identity operations), it would be good to find a way to also make it possible for the application using the PAM stack to find out which domain (and thus which identity) sssd actually used. So for "login", was it "login@emea.example.com" or "login@hq.example.com" that was used?
Do we have a way to return the information to the application?
Maybe via pam_putenv or even putenv?
There seems to be already interfaces to put information from the responder side easily to the responder message information which later get then set by the pam_sss client either as pam_putenv or putenv or both. So we could set something like that:
SSSD_DOMAIN=emea.example.com
... as pamenv or regular environment variable - or both.
Would we want to have this configurable - if the environment would be set? If so, do we want to have this in sssd.conf or via pam_sss modules arguments?
On Tue, Jul 29, 2014 at 04:15:16PM +0200, Daniel Gollub wrote:
Now that we have a design document on the list, let me include a couple of nitpicks, which might be nice to fix in the next iteration..
Signed-off-by: Daniel Gollub dgollub@brocade.com Reviewed-by: Sven-Thorsten Dietrich sven@brocade.com
src/providers/data_provider.h | 1 + src/responder/pam/pamsrv_cmd.c | 44 +++++++++++++++++++++++++++++++++++++++++- src/sss_client/pam_sss.c | 29 ++++++++++++++++++++++++++-- src/sss_client/sss_cli.h | 1 + 4 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index ebb4fad..0abfd0f 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -170,6 +170,7 @@ struct pam_data { char *tty; char *ruser; char *rhost;
- char **requested_domains; struct sss_auth_token *authtok; struct sss_auth_token *newauthtok; uint32_t cli_pid;
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 140d541..c6539e5 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -44,6 +44,26 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
+static bool is_domain_requested(struct pam_data *pd, const char *domain_name) +{
- int i;
- /* If none specific domains got requested via pam, all domains are allowed.
* Which mimics the default/original behaviour.*/- if (!pd->requested_domains)
return true;
We prefer to use curly brackets around one-line statements, too: if (!pd->requested_domains) { return true; }
It's mostly defensive coding so that when the single-line statement becomes multi-line, we don't forget to add the brackets as well..
- for (i = 0; pd->requested_domains[i]; i++) {
if (strcmp(domain_name, pd->requested_domains[i]))
same here.
continue;return true;- }
- return false;
+}
static int extract_authtok_v2(struct sss_auth_token *tok, size_t data_size, uint8_t *body, size_t blen, size_t *c) @@ -146,6 +166,7 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, int ret; uint32_t start; uint32_t terminator;
char *requested_domains;
if (blen < 4*sizeof(uint32_t)+2) { DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
@@ -202,6 +223,16 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, ret = extract_string(&pd->rhost, size, body, blen, &c); if (ret != EOK) return ret; break;
case SSS_PAM_ITEM_REQUESTED_DOMAINS:ret = extract_string(&requested_domains, size, body, blen, &c);if (ret != EOK) return ret;
This case is I think OK, (return on the same line as if) I would just put a newline after the if, but that's more of a personal preference.
ret = split_on_separator(pd, requested_domains, ',', true, true,&pd->requested_domains, NULL);if (ret != EOK) {DEBUG(1, ("Failed to parse requested_domains list!\n"));
We have converted our DEBUG macros to a new SSSDBG_ constants instead of numbers and no longer need to wrap the DEBUG body in (). It would be nice to use the same pattern in your patch.
return ret;}break; case SSS_PAM_ITEM_CLI_PID: ret = extract_uint32_t(&pd->cli_pid, size, body, blen, &c);@@ -836,12 +867,22 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) ret = ENOENT; goto done; }
/* skip this domain if not requested */if (!is_domain_requested(pd, dom->name)) {ret = ENOENT;goto done;} } else { for (dom = preq->cctx->rctx->domains; dom; dom = get_next_domain(dom, false)) { if (dom->fqnames) continue;
/* skip this domain if not requested */if (!is_domain_requested(pd, dom->name))continue;
Single-line statement again.
ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout, dom, pd->user); if (ncret == ENOENT) {@@ -856,7 +897,8 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) "User [%s@%s] filtered out (negative cache). " "Trying next domain.\n", pd->user, dom->name); }
if (!dom) {
if (!dom || !is_domain_requested(pd, dom->name)) { ret = ENOENT; goto done; }diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index d2502d1..4d76bd2 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -58,6 +58,7 @@ #define PW_RESET_MSG_MAX_SIZE 4096
#define OPT_RETRY_KEY "retry=" +#define OPT_DOMAINS_KEY "domains="
struct pam_items { const char* pam_service; @@ -81,6 +82,8 @@ struct pam_items { pid_t cli_pid; const char *login_name; char *domain_name;
- const char *requested_domains;
- size_t requested_domains_size;
};
#define DEBUG_MGS_LEN 1024 @@ -246,6 +249,9 @@ static int pack_message_v3(struct pam_items *pi, size_t *size, len += pi->pam_newauthtok != NULL ? 3*sizeof(uint32_t) + pi->pam_newauthtok_size : 0; len += 3*sizeof(uint32_t); /* cli_pid */
len += *pi->requested_domains != '\0' ?
2*sizeof(uint32_t) + pi->requested_domains_size : 0;buf = malloc(len); if (buf == NULL) {
@@ -271,6 +277,9 @@ static int pack_message_v3(struct pam_items *pi, size_t *size, rp += add_string_item(SSS_PAM_ITEM_RHOST, pi->pam_rhost, pi->pam_rhost_size, &buf[rp]);
- rp += add_string_item(SSS_PAM_ITEM_REQUESTED_DOMAINS, pi->requested_domains, pi->requested_domains_size,
&buf[rp]);- rp += add_uint32_t_item(SSS_PAM_ITEM_CLI_PID, (uint32_t) pi->cli_pid, &buf[rp]);
@@ -1061,6 +1070,9 @@ static int get_pam_items(pam_handle_t *pamh, struct pam_items *pi)
pi->domain_name = NULL;
- if (pi->requested_domains == NULL) pi->requested_domains="";
- pi->requested_domains_size=strlen(pi->requested_domains)+1;
Can you put a space before and after the equals sign? Like: pi->requested_domains_size = strlen(pi->requested_domains) + 1;
The rest looks good. Thanks again for the patch.
sssd-devel@lists.fedorahosted.org