Blob Blame History Raw
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