From 663fd9bcdcc6b299785ba3434532cd7e6c462bff Mon Sep 17 00:00:00 2001 From: Daniel Gollub Date: Sep 29 2014 16:27:16 +0000 Subject: PAM: Add domains= option to pam_sss Design document: https://fedorahosted.org/sssd/wiki/DesignDocs/RestrictDomainsInPAM Fixes: https://fedorahosted.org/sssd/ticket/1021 Signed-off-by: Pavel Reichl Reviewed-by: Sven-Thorsten Dietrich Reviewed-by: Jakub Hrozek Reviewed-by: Lukáš Slebodník --- diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index b127985..ec5b79d 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -172,6 +172,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 eb6953a..c135e3c 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -44,6 +44,28 @@ 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) @@ -143,6 +165,7 @@ static int pam_parse_in_data_v2(struct pam_data *pd, 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"); @@ -194,6 +217,20 @@ static int pam_parse_in_data_v2(struct pam_data *pd, 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(SSSDBG_CRIT_FAILURE, + "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); @@ -879,6 +916,12 @@ 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, pd->domain)) { + ret = ENOENT; + goto done; + } } else { for (dom = preq->cctx->rctx->domains; dom; @@ -896,6 +939,11 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) 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) { @@ -910,7 +958,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..abe9b05 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 = ""; + } 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 a0c635f..edb520c 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