From 9f5fbbdac3658f5f1695fbf3cf89544b4b578b92 Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik <lslebodn@redhat.com> Date: Wed, 20 Jan 2016 13:15:11 +0100 Subject: [PATCH 7/7] PAM: Allow to configure pam services for Smartcards Resolves: https://pagure.io/SSSD/sssd/issue/2926 Merges: https://pagure.io/SSSD/sssd/pull-request/3799 Reviewed-by: Sumit Bose <sbose@redhat.com> (cherry picked from commit 93caaf294cfd85b4e0d7faa2fc5c2298d6b13020) --- src/confdb/confdb.h | 1 + src/config/SSSDConfig/__init__.py.in | 1 + src/config/cfg_rules.ini | 1 + src/config/etc/sssd.api.conf | 1 + src/man/sssd.conf.5.xml | 76 +++++++++++++++- src/responder/pam/pamsrv.h | 1 + src/responder/pam/pamsrv_p11.c | 164 +++++++++++++++++++++++++++++++++-- 7 files changed, 237 insertions(+), 8 deletions(-) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 8af625f..700ab76 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -131,6 +131,7 @@ #define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path" #define CONFDB_PAM_P11_CHILD_TIMEOUT "p11_child_timeout" #define CONFDB_PAM_APP_SERVICES "pam_app_services" +#define CONFDB_PAM_P11_ALLOWED_SERVICES "pam_p11_allowed_services" /* SUDO */ #define CONFDB_SUDO_CONF_ENTRY "config/sudo" diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 32b74e4..2846ea2 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -103,6 +103,7 @@ option_strings = { 'pam_cert_db_path' : _('Path to certificate database with PKCS#11 modules.'), 'p11_child_timeout' : _('How many seconds will pam_sss wait for p11_child to finish'), 'pam_app_services' : _('Which PAM services are permitted to contact application domains'), + 'pam_p11_allowed_services' : _('Allowed services for using smartcards'), # [sudo] 'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'), diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index 5513227..c18fcbd 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -126,6 +126,7 @@ option = pam_cert_auth option = pam_cert_db_path option = p11_child_timeout option = pam_app_services +option = pam_p11_allowed_services [rule/allowed_sudo_options] validator = ini_allowed_options diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index 2be2e3e..7156142 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -75,6 +75,7 @@ pam_cert_auth = bool, None, false pam_cert_db_path = str, None, false p11_child_timeout = int, None, false pam_app_services = str, None, false +pam_p11_allowed_services = str, None, false [sudo] # sudo service diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index ed3c100..881ffc6 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -1389,7 +1389,81 @@ pam_account_locked_message = Account locked, please contact help desk. </para> </listitem> </varlistentry> - + <varlistentry> + <term>pam_p11_allowed_services (integer)</term> + <listitem> + <para> + A comma-separated list of PAM service names for + which it will be allowed to use Smartcards. + </para> + <para> + It is possible to add another PAM service name to + the default set by using + <quote>+service_name</quote> or to explicitly + remove a PAM service name from the default set by + using <quote>-service_name</quote>. For example, + in order to replace a default PAM service name for + authentication with Smartcards + (e.g. <quote>login</quote>) with a custom PAM + service name (e.g. <quote>my_pam_service</quote>), + you would use the following configuration: + <programlisting> +pam_p11_allowed_services = +my_pam_service, -login + </programlisting> + </para> + <para> + Default: the default set of PAM service names + includes: + <itemizedlist> + <listitem> + <para> + login + </para> + </listitem> + <listitem> + <para> + su + </para> + </listitem> + <listitem> + <para> + su-l + </para> + </listitem> + <listitem> + <para> + gdm-smartcard + </para> + </listitem> + <listitem> + <para> + gdm-password + </para> + </listitem> + <listitem> + <para> + kdm + </para> + </listitem> + <listitem> + <para> + sudo + </para> + </listitem> + <listitem> + <para> + sudo-i + </para> + </listitem> + <listitem> + <para> + gnome-screensaver + </para> + </listitem> + </itemizedlist> + </para> + </listitem> + </varlistentry> </variablelist> </refsect2> diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index dfd9821..3325d9b 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -51,6 +51,7 @@ struct pam_ctx { int p11_child_debug_fd; char *nss_db; struct sss_certmap_ctx *sss_certmap_ctx; + char **smartcard_services; }; struct pam_auth_dp_req { diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c index 0b6a162..ddb2def 100644 --- a/src/responder/pam/pamsrv_p11.c +++ b/src/responder/pam/pamsrv_p11.c @@ -224,12 +224,148 @@ errno_t p11_child_init(struct pam_ctx *pctx) return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd); } +static inline bool +service_in_list(char **list, size_t nlist, const char *str) +{ + size_t i; + + for (i = 0; i < nlist; i++) { + if (strcasecmp(list[i], str) == 0) { + break; + } + } + + return (i < nlist) ? true : false; +} + +static errno_t get_sc_services(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx, + char ***_sc_list) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + char *conf_str; + char **conf_list; + int conf_list_size; + char **add_list; + char **remove_list; + int ai = 0; + int ri = 0; + int j = 0; + char **sc_list; + int expected_sc_list_size; + + const char *default_sc_services[] = { + "login", "su", "su-l", "gdm-smartcard", "gdm-password", "kdm", "sudo", + "sudo-i", "gnome-screensaver", NULL, + }; + const int default_sc_services_size = + sizeof(default_sc_services) / sizeof(default_sc_services[0]); + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = confdb_get_string(pctx->rctx->cdb, tmp_ctx, CONFDB_PAM_CONF_ENTRY, + CONFDB_PAM_P11_ALLOWED_SERVICES, NULL, + &conf_str); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "confdb_get_string failed %d [%s]\n", ret, sss_strerror(ret)); + goto done; + } + + if (conf_str != NULL) { + ret = split_on_separator(tmp_ctx, conf_str, ',', true, true, + &conf_list, &conf_list_size); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot parse list of service names '%s': %d [%s]\n", + conf_str, ret, sss_strerror(ret)); + goto done; + } + } else { + conf_list = talloc_zero_array(tmp_ctx, char *, 1); + conf_list_size = 0; + } + + add_list = talloc_zero_array(tmp_ctx, char *, conf_list_size + 1); + remove_list = talloc_zero_array(tmp_ctx, char *, conf_list_size + 1); + + if (add_list == NULL || remove_list == NULL) { + ret = ENOMEM; + goto done; + } + + for (int i = 0; conf_list[i] != NULL; ++i) { + switch (conf_list[i][0]) { + case '+': + add_list[ai] = conf_list[i] + 1; + ++ai; + break; + case '-': + remove_list[ri] = conf_list[i] + 1; + ++ri; + break; + default: + DEBUG(SSSDBG_OP_FAILURE, + "The option "CONFDB_PAM_P11_ALLOWED_SERVICES" must start" + "with either '+' (for adding service) or '-' (for " + "removing service) got '%s'\n", conf_list[i]); + ret = EINVAL; + goto done; + } + } + + expected_sc_list_size = default_sc_services_size + ai + 1; + + sc_list = talloc_zero_array(tmp_ctx, char *, expected_sc_list_size); + if (sc_list == NULL) { + ret = ENOMEM; + goto done; + } + + for (int i = 0; add_list[i] != NULL; ++i) { + if (service_in_list(remove_list, ri, add_list[i])) { + continue; + } + + sc_list[j] = talloc_strdup(sc_list, add_list[i]); + if (sc_list[j] == NULL) { + ret = ENOMEM; + goto done; + } + ++j; + } + + for (int i = 0; default_sc_services[i] != NULL; ++i) { + if (service_in_list(remove_list, ri, default_sc_services[i])) { + continue; + } + + sc_list[j] = talloc_strdup(sc_list, default_sc_services[i]); + if (sc_list[j] == NULL) { + ret = ENOMEM; + goto done; + } + ++j; + } + + if (_sc_list != NULL) { + *_sc_list = talloc_steal(mem_ctx, sc_list); + } + +done: + talloc_zfree(tmp_ctx); + + return ret; +} + bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd) { size_t c; - const char *sc_services[] = { "login", "su", "su-l", "gdm-smartcard", - "gdm-password", "kdm", "sudo", "sudo-i", - "gnome-screensaver", NULL }; + errno_t ret; + if (!pctx->cert_auth) { return false; } @@ -244,16 +380,30 @@ bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd) return false; } - /* TODO: make services configurable */ if (pd->service == NULL || *pd->service == '\0') { return false; } - for (c = 0; sc_services[c] != NULL; c++) { - if (strcmp(pd->service, sc_services[c]) == 0) { + + /* Initialize smartcard allowed services just once */ + if (pctx->smartcard_services == NULL) { + ret = get_sc_services(pctx, pctx, &pctx->smartcard_services); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to get p11 allowed services %d[%s]", + ret, sss_strerror(ret)); + sss_log(SSS_LOG_ERR, + "Failed to evaluate pam_p11_allowed_services option, " + "please check for typos in the SSSD configuration"); + return false; + } + } + + for (c = 0; pctx->smartcard_services[c] != NULL; c++) { + if (strcmp(pd->service, pctx->smartcard_services[c]) == 0) { break; } } - if (sc_services[c] == NULL) { + if (pctx->smartcard_services[c] == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Smartcard authentication for service [%s] not supported.\n", pd->service); -- 2.9.5