Blame SOURCES/0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch

bb7cd1
From 3f32e79858f268ce6501de44e5158e8c12f688dd Mon Sep 17 00:00:00 2001
bb7cd1
From: Jakub Hrozek <jhrozek@redhat.com>
bb7cd1
Date: Wed, 22 Mar 2017 13:01:18 +0100
bb7cd1
Subject: [PATCH 72/72] KRB5: Authenticate users in a non-POSIX domain using a
bb7cd1
 MEMORY ccache
bb7cd1
bb7cd1
Related to:
bb7cd1
https://pagure.io/SSSD/sssd/issue/3310
bb7cd1
bb7cd1
The following changes were done to the Kerberos authentication code
bb7cd1
in order to support authentication in a non-POSIX environment:
bb7cd1
    - delayed authentication is disabled in non-POSIX domains
bb7cd1
    - when a user logs in in a non-POSIX domain, SSSD uses a
bb7cd1
      MEMORY:$username ccache and destroys is then krb5_child finishes
bb7cd1
      so that just the numeric result is used
bb7cd1
    - krb5_child doesn't drop privileges in this configuration because
bb7cd1
      there is nothing to drop privileges to
bb7cd1
bb7cd1
Reviewed-by: Sumit Bose <sbose@redhat.com>
bb7cd1
---
bb7cd1
 src/providers/krb5/krb5_auth.c                     | 62 ++++++++++++++++------
bb7cd1
 src/providers/krb5/krb5_auth.h                     |  2 +
bb7cd1
 src/providers/krb5/krb5_child.c                    | 32 +++++++++--
bb7cd1
 src/providers/krb5/krb5_child_handler.c            | 15 +++++-
bb7cd1
 .../krb5/krb5_delayed_online_authentication.c      |  7 +++
bb7cd1
 src/providers/krb5/krb5_init.c                     |  3 ++
bb7cd1
 6 files changed, 99 insertions(+), 22 deletions(-)
bb7cd1
bb7cd1
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
bb7cd1
index c2d6d7eeacc1f766024c4d629f25fd0f0be24e5e..2faf18d17a735476c20f9cc27b15be4a39cadc5c 100644
bb7cd1
--- a/src/providers/krb5/krb5_auth.c
bb7cd1
+++ b/src/providers/krb5/krb5_auth.c
bb7cd1
@@ -42,6 +42,8 @@
bb7cd1
 #include "providers/krb5/krb5_utils.h"
bb7cd1
 #include "providers/krb5/krb5_ccache.h"
bb7cd1
 
bb7cd1
+#define  NON_POSIX_CCNAME_FMT       "MEMORY:sssd_nonposix_dummy_%u"
bb7cd1
+
bb7cd1
 static int krb5_mod_ccname(TALLOC_CTX *mem_ctx,
bb7cd1
                            struct sysdb_ctx *sysdb,
bb7cd1
                            struct sss_domain_info *domain,
bb7cd1
@@ -200,6 +202,7 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx,
bb7cd1
     talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
bb7cd1
 
bb7cd1
     kr->pd = pd;
bb7cd1
+    kr->dom = dom;
bb7cd1
     kr->krb5_ctx = krb5_ctx;
bb7cd1
 
bb7cd1
     ret = get_krb_primary(krb5_ctx->name_to_primary,
bb7cd1
@@ -275,8 +278,11 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
bb7cd1
         return;
bb7cd1
     }
bb7cd1
 
bb7cd1
-    ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid);
bb7cd1
-    if (ret != EOK) {
bb7cd1
+    ret = add_user_to_delayed_online_authentication(krb5_ctx, domain, pd, uid);
bb7cd1
+    if (ret == ENOTSUP) {
bb7cd1
+        /* This error is not fatal */
bb7cd1
+        DEBUG(SSSDBG_MINOR_FAILURE, "Delayed authentication not supported\n");
bb7cd1
+    } else if (ret != EOK) {
bb7cd1
         /* This error is not fatal */
bb7cd1
         DEBUG(SSSDBG_CRIT_FAILURE,
bb7cd1
               "add_user_to_delayed_online_authentication failed.\n");
bb7cd1
@@ -291,21 +297,43 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
bb7cd1
 {
bb7cd1
     const char *ccname_template;
bb7cd1
 
bb7cd1
-    ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
bb7cd1
+    switch (kr->dom->type) {
bb7cd1
+    case DOM_TYPE_POSIX:
bb7cd1
+        ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
bb7cd1
 
bb7cd1
-    kr->ccname = expand_ccname_template(kr, kr, ccname_template,
bb7cd1
-                                        kr->krb5_ctx->illegal_path_re, true,
bb7cd1
-                                        be_ctx->domain->case_sensitive);
bb7cd1
-    if (kr->ccname == NULL) {
bb7cd1
-        DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
bb7cd1
-        return ENOMEM;
bb7cd1
-    }
bb7cd1
+        kr->ccname = expand_ccname_template(kr, kr, ccname_template,
bb7cd1
+                                            kr->krb5_ctx->illegal_path_re, true,
bb7cd1
+                                            be_ctx->domain->case_sensitive);
bb7cd1
+        if (kr->ccname == NULL) {
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
bb7cd1
+            return ENOMEM;
bb7cd1
+        }
bb7cd1
 
bb7cd1
-    kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
bb7cd1
-                                                 SYSDB_CCACHE_FILE, NULL);
bb7cd1
-    if (kr->old_ccname == NULL) {
bb7cd1
-        DEBUG(SSSDBG_TRACE_LIBS,
bb7cd1
-                "No ccache file for user [%s] found.\n", kr->pd->user);
bb7cd1
+        kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
bb7cd1
+                                                    SYSDB_CCACHE_FILE, NULL);
bb7cd1
+        if (kr->old_ccname == NULL) {
bb7cd1
+            DEBUG(SSSDBG_TRACE_LIBS,
bb7cd1
+                    "No ccache file for user [%s] found.\n", kr->pd->user);
bb7cd1
+        }
bb7cd1
+        break;
bb7cd1
+    case DOM_TYPE_APPLICATION:
bb7cd1
+        DEBUG(SSSDBG_TRACE_FUNC,
bb7cd1
+               "Domain type application, will use in-memory ccache\n");
bb7cd1
+        /* We don't care about using cryptographic randomness, just
bb7cd1
+         * a non-predictable ccname, so using rand() here is fine
bb7cd1
+         */
bb7cd1
+        kr->ccname = talloc_asprintf(kr,
bb7cd1
+                                     NON_POSIX_CCNAME_FMT,
bb7cd1
+                                     rand() % UINT_MAX);
bb7cd1
+        if (kr->ccname == NULL) {
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
bb7cd1
+            return ENOMEM;
bb7cd1
+        }
bb7cd1
+
bb7cd1
+        break;
bb7cd1
+    default:
bb7cd1
+        DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported domain type\n");
bb7cd1
+        return EINVAL;
bb7cd1
     }
bb7cd1
 
bb7cd1
     return EOK;
bb7cd1
@@ -617,7 +645,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
bb7cd1
         kr->uid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
bb7cd1
                                                        res->msgs[0],
bb7cd1
                                                        SYSDB_UIDNUM, 0);
bb7cd1
-        if (kr->uid == 0) {
bb7cd1
+        if (kr->uid == 0 && state->domain->type == DOM_TYPE_POSIX) {
bb7cd1
             DEBUG(SSSDBG_CONF_SETTINGS,
bb7cd1
                   "UID for user [%s] not known.\n", pd->user);
bb7cd1
             ret = ENOENT;
bb7cd1
@@ -627,7 +655,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
bb7cd1
         kr->gid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
bb7cd1
                                                        res->msgs[0],
bb7cd1
                                                        SYSDB_GIDNUM, 0);
bb7cd1
-        if (kr->gid == 0) {
bb7cd1
+        if (kr->gid == 0 && state->domain->type == DOM_TYPE_POSIX) {
bb7cd1
             DEBUG(SSSDBG_CONF_SETTINGS,
bb7cd1
                   "GID for user [%s] not known.\n", pd->user);
bb7cd1
             ret = ENOENT;
bb7cd1
diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h
bb7cd1
index 75ad916e79b29043120543ab3c4c1bd27e09d913..8ad3aeff21e58f9055ae144eaa450992c6391ba6 100644
bb7cd1
--- a/src/providers/krb5/krb5_auth.h
bb7cd1
+++ b/src/providers/krb5/krb5_auth.h
bb7cd1
@@ -50,6 +50,7 @@
bb7cd1
 struct krb5child_req {
bb7cd1
     struct pam_data *pd;
bb7cd1
     struct krb5_ctx *krb5_ctx;
bb7cd1
+    struct sss_domain_info *dom;
bb7cd1
 
bb7cd1
     const char *ccname;
bb7cd1
     const char *old_ccname;
bb7cd1
@@ -118,6 +119,7 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len,
bb7cd1
                           struct krb5_child_response **_res);
bb7cd1
 
bb7cd1
 errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
bb7cd1
+                                                  struct sss_domain_info *domain,
bb7cd1
                                                   struct pam_data *pd,
bb7cd1
                                                   uid_t uid);
bb7cd1
 errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
bb7cd1
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
bb7cd1
index a4128dda6b0861a95dba223047d66c4158b1afb6..cbbc892bee0365892ac66d3654c974d325166b60 100644
bb7cd1
--- a/src/providers/krb5/krb5_child.c
bb7cd1
+++ b/src/providers/krb5/krb5_child.c
bb7cd1
@@ -80,6 +80,7 @@ struct krb5_req {
bb7cd1
     char *ccname;
bb7cd1
     char *keytab;
bb7cd1
     bool validate;
bb7cd1
+    bool posix_domain;
bb7cd1
     bool send_pac;
bb7cd1
     bool use_enterprise_princ;
bb7cd1
     char *fast_ccname;
bb7cd1
@@ -102,6 +103,16 @@ struct krb5_req {
bb7cd1
 static krb5_context krb5_error_ctx;
bb7cd1
 #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
bb7cd1
 
bb7cd1
+static errno_t k5c_become_user(uid_t uid, gid_t gid, bool is_posix)
bb7cd1
+{
bb7cd1
+    if (is_posix == false) {
bb7cd1
+        DEBUG(SSSDBG_TRACE_FUNC,
bb7cd1
+              "Will not drop privileges for a non-POSIX user\n");
bb7cd1
+        return EOK;
bb7cd1
+    }
bb7cd1
+    return become_user(uid, gid);
bb7cd1
+}
bb7cd1
+
bb7cd1
 static krb5_error_code set_lifetime_options(struct cli_opts *cli_opts,
bb7cd1
                                             krb5_get_init_creds_opt *options)
bb7cd1
 {
bb7cd1
@@ -1561,6 +1572,15 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
bb7cd1
         DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n");
bb7cd1
     }
bb7cd1
 
bb7cd1
+    /* In a non-POSIX environment, we only care about the return code from
bb7cd1
+     * krb5_child, so let's not even attempt to create the ccache
bb7cd1
+     */
bb7cd1
+    if (kr->posix_domain == false) {
bb7cd1
+        DEBUG(SSSDBG_TRACE_LIBS,
bb7cd1
+              "Finished authentication in a non-POSIX domain\n");
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
     /* If kr->ccname is cache collection (DIR:/...), we want to work
bb7cd1
      * directly with file ccache (DIR::/...), but cache collection
bb7cd1
      * should be returned back to back end.
bb7cd1
@@ -2146,6 +2166,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
bb7cd1
     size_t p = 0;
bb7cd1
     uint32_t len;
bb7cd1
     uint32_t validate;
bb7cd1
+    uint32_t posix_domain;
bb7cd1
     uint32_t send_pac;
bb7cd1
     uint32_t use_enterprise_princ;
bb7cd1
     struct pam_data *pd;
bb7cd1
@@ -2167,6 +2188,8 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
bb7cd1
     SAFEALIGN_COPY_UINT32_CHECK(&kr->gid, buf + p, size, &p);
bb7cd1
     SAFEALIGN_COPY_UINT32_CHECK(&validate, buf + p, size, &p);
bb7cd1
     kr->validate = (validate == 0) ? false : true;
bb7cd1
+    SAFEALIGN_COPY_UINT32_CHECK(&posix_domain, buf + p, size, &p);
bb7cd1
+    kr->posix_domain = (posix_domain == 0) ? false : true;
bb7cd1
     SAFEALIGN_COPY_UINT32_CHECK(offline, buf + p, size, &p);
bb7cd1
     SAFEALIGN_COPY_UINT32_CHECK(&send_pac, buf + p, size, &p);
bb7cd1
     kr->send_pac = (send_pac == 0) ? false : true;
bb7cd1
@@ -2331,6 +2354,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
bb7cd1
                                          krb5_context ctx,
bb7cd1
                                          uid_t fast_uid,
bb7cd1
                                          gid_t fast_gid,
bb7cd1
+                                         bool posix_domain,
bb7cd1
                                          struct cli_opts *cli_opts,
bb7cd1
                                          const char *primary,
bb7cd1
                                          const char *realm,
bb7cd1
@@ -2420,7 +2444,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
bb7cd1
                 /* Try to carry on */
bb7cd1
             }
bb7cd1
 
bb7cd1
-            kerr = become_user(fast_uid, fast_gid);
bb7cd1
+            kerr = k5c_become_user(fast_uid, fast_gid, posix_domain);
bb7cd1
             if (kerr != 0) {
bb7cd1
                 DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed: %d\n", kerr);
bb7cd1
                 exit(1);
bb7cd1
@@ -2572,7 +2596,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
bb7cd1
     }
bb7cd1
 
bb7cd1
     kerr = check_fast_ccache(kr, kr->ctx, kr->fast_uid, kr->fast_gid,
bb7cd1
-                             kr->cli_opts,
bb7cd1
+                             kr->posix_domain, kr->cli_opts,
bb7cd1
                              fast_principal, fast_principal_realm,
bb7cd1
                              kr->keytab, &kr->fast_ccname);
bb7cd1
     if (kerr != 0) {
bb7cd1
@@ -2773,7 +2797,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
bb7cd1
          * the user who is logging in. The same applies to the offline case
bb7cd1
          * the user who is logging in. The same applies to the offline case.
bb7cd1
          */
bb7cd1
-        kerr = become_user(kr->uid, kr->gid);
bb7cd1
+        kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain);
bb7cd1
         if (kerr != 0) {
bb7cd1
             DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
bb7cd1
             return kerr;
bb7cd1
@@ -3075,7 +3099,7 @@ int main(int argc, const char *argv[])
bb7cd1
     if ((sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
bb7cd1
             && sss_authtok_get_type(kr->pd->authtok)
bb7cd1
                                         != SSS_AUTHTOK_TYPE_SC_KEYPAD)) {
bb7cd1
-        kerr = become_user(kr->uid, kr->gid);
bb7cd1
+        kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain);
bb7cd1
         if (kerr != 0) {
bb7cd1
             DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
bb7cd1
             ret = EFAULT;
bb7cd1
diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
bb7cd1
index 680e67b089fcb32280352af24aae35af133a52f3..87e79a06e917aadb622455bccfc2e9c6769f70c2 100644
bb7cd1
--- a/src/providers/krb5/krb5_child_handler.c
bb7cd1
+++ b/src/providers/krb5/krb5_child_handler.c
bb7cd1
@@ -107,6 +107,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
bb7cd1
     uint32_t validate;
bb7cd1
     uint32_t send_pac;
bb7cd1
     uint32_t use_enterprise_principal;
bb7cd1
+    uint32_t posix_domain;
bb7cd1
     size_t username_len = 0;
bb7cd1
     errno_t ret;
bb7cd1
 
bb7cd1
@@ -131,6 +132,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
bb7cd1
             break;
bb7cd1
     }
bb7cd1
 
bb7cd1
+    switch (kr->dom->type) {
bb7cd1
+    case DOM_TYPE_POSIX:
bb7cd1
+        posix_domain = 1;
bb7cd1
+        break;
bb7cd1
+    case DOM_TYPE_APPLICATION:
bb7cd1
+        posix_domain = 0;
bb7cd1
+        break;
bb7cd1
+    default:
bb7cd1
+        return EINVAL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
     if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) {
bb7cd1
         use_enterprise_principal = false;
bb7cd1
     } else {
bb7cd1
@@ -151,7 +163,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
bb7cd1
         kr->pd->cmd == SSS_CMD_RENEW ||
bb7cd1
         kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
bb7cd1
         kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
bb7cd1
-        buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
bb7cd1
+        buf->size += 5*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
bb7cd1
                      sss_authtok_get_size(kr->pd->authtok);
bb7cd1
 
bb7cd1
         buf->size += sizeof(uint32_t);
bb7cd1
@@ -182,6 +194,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
bb7cd1
     SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp);
bb7cd1
     SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp);
bb7cd1
     SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp);
bb7cd1
+    SAFEALIGN_COPY_UINT32(&buf->data[rp], &posix_domain, &rp);
bb7cd1
     SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp);
bb7cd1
     SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp);
bb7cd1
     SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp);
bb7cd1
diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c
bb7cd1
index bf2ef775573ba6bad79a99ad43b5d9748516e794..1cb7eade0e4cb9afbc4d031a07b3519ba08456d6 100644
bb7cd1
--- a/src/providers/krb5/krb5_delayed_online_authentication.c
bb7cd1
+++ b/src/providers/krb5/krb5_delayed_online_authentication.c
bb7cd1
@@ -234,6 +234,7 @@ static void delayed_online_authentication_callback(void *private_data)
bb7cd1
 }
bb7cd1
 
bb7cd1
 errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
bb7cd1
+                                                  struct sss_domain_info *domain,
bb7cd1
                                                   struct pam_data *pd,
bb7cd1
                                                   uid_t uid)
bb7cd1
 {
bb7cd1
@@ -242,6 +243,12 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
bb7cd1
     hash_value_t value;
bb7cd1
     struct pam_data *new_pd;
bb7cd1
 
bb7cd1
+    if (domain->type != DOM_TYPE_POSIX) {
bb7cd1
+        DEBUG(SSSDBG_MINOR_FAILURE,
bb7cd1
+              "Domain type does not support delayed authentication\n");
bb7cd1
+        return ENOTSUP;
bb7cd1
+    }
bb7cd1
+
bb7cd1
     if (krb5_ctx->deferred_auth_ctx == NULL) {
bb7cd1
         DEBUG(SSSDBG_CRIT_FAILURE,
bb7cd1
               "Missing context for delayed online authentication.\n");
bb7cd1
diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c
bb7cd1
index 12c8dfcc49af75de619ec0858aaff81504698273..66ae68fb4773af3987f2062246bc6493107c74d5 100644
bb7cd1
--- a/src/providers/krb5/krb5_init.c
bb7cd1
+++ b/src/providers/krb5/krb5_init.c
bb7cd1
@@ -136,6 +136,9 @@ errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx,
bb7cd1
         return ENOMEM;
bb7cd1
     }
bb7cd1
 
bb7cd1
+    /* Only needed to generate random ccache names for non-POSIX domains */
bb7cd1
+    srand(time(NULL) * getpid());
bb7cd1
+
bb7cd1
     ret = sss_krb5_get_options(ctx, be_ctx->cdb, be_ctx->conf_path, &ctx->opts);
bb7cd1
     if (ret != EOK) {
bb7cd1
         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get krb5 options [%d]: %s\n",
bb7cd1
-- 
bb7cd1
2.9.3
bb7cd1