[SSSD] [PATCH] Do not overwrite valid TGTs when offline

Sumit Bose sbose at redhat.com
Fri Dec 18 13:51:16 UTC 2009


On Fri, Dec 18, 2009 at 08:25:26AM -0500, Stephen Gallagher wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> On 12/17/2009 07:27 AM, Sumit Bose wrote:
> > Hi,
> > 
> > this patch should fix #327.
> > 
> > Currently an empty ticket is created if the client is offline. This
> > patch checks if there already is a ccache file and if it contains a
> > valid, i.e not expired, TGT. If this is true the ccache file and the TGT
> > are used.
> > 
> > bye,
> > Sumit
> > 
> 
> Nack.
> 
> (Fri Dec 18 08:24:05 2009) [sssd[be[redhat.com]]] [load_backend_module]
> (0): Unable to load krb5 module with path
> (/usr/lib64/sssd/libsss_krb5.so), error: /usr/lib64/sssd/libsss_krb5.so:
> undefined symbol: check_for_valid_tgt
> 
> This crashes the backend.
> 
> - -- 
> Stephen Gallagher
> RHCE 804006346421761
> 
> Delivering value year after year.
> Red Hat ranks #1 in value among software vendors.
> http://www.redhat.com/promo/vendor/
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.10 (GNU/Linux)
> Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
> 
> iEYEARECAAYFAksrgsIACgkQeiVVYja6o6Nm3ACeJIJNsOHnhrehCcvzGL7UXIFa
> 13AAoJ8JolOv16XKgdziDSFh4Bev3Dz7
> =jBI8
> -----END PGP SIGNATURE-----

aah, sorry, I forgot to put the Makefile.am change into the patch, now
they are in.

bye,
Sumit
-------------- next part --------------
From 10e658339cff9a0bf6fdc88a0809ebb2515a761e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 17 Dec 2009 13:18:05 +0100
Subject: [PATCH] Do not overwrite valid TGTs when offline

---
 server/Makefile.am                |    3 +-
 server/providers/krb5/krb5_auth.c |  129 +++++++++++++++++++++++++------------
 server/providers/krb5/krb5_auth.h |    1 +
 server/util/sss_krb5.c            |   92 ++++++++++++++++++++++++++
 server/util/sss_krb5.h            |    3 +
 5 files changed, 185 insertions(+), 43 deletions(-)

diff --git a/server/Makefile.am b/server/Makefile.am
index a7fd8c4..9d17ee7 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -618,7 +618,8 @@ libsss_krb5_la_SOURCES = \
     providers/krb5/krb5_become_user.c \
     providers/krb5/krb5_auth.c \
     providers/krb5/krb5_common.c \
-    providers/krb5/krb5_init.c
+    providers/krb5/krb5_init.c \
+    util/sss_krb5.c
 libsss_krb5_la_CFLAGS = \
     $(AM_CFLAGS) \
     $(DHASH_CFLAGS)
diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c
index 7301841..6e63c30 100644
--- a/server/providers/krb5/krb5_auth.c
+++ b/server/providers/krb5/krb5_auth.c
@@ -113,7 +113,8 @@ done:
     return ret;
 }
 
-static errno_t check_if_ccache_file_is_used(uid_t uid, const char **ccname)
+static errno_t check_if_ccache_file_is_used(uid_t uid, const char *ccname,
+                                            bool *result)
 {
     int ret;
     size_t offset = 0;
@@ -121,15 +122,17 @@ static errno_t check_if_ccache_file_is_used(uid_t uid, const char **ccname)
     const char *filename;
     bool active;
 
-    if (ccname == NULL || *ccname == NULL) {
+    *result = false;
+
+    if (ccname == NULL || *ccname == '\0') {
         return EINVAL;
     }
 
-    if (strncmp(*ccname, "FILE:", 5) == 0) {
+    if (strncmp(ccname, "FILE:", 5) == 0) {
         offset = 5;
     }
 
-    filename = *ccname + offset;
+    filename = ccname + offset;
 
     if (filename[0] != '/') {
         DEBUG(1, ("Only absolute path names are allowed"));
@@ -142,7 +145,6 @@ static errno_t check_if_ccache_file_is_used(uid_t uid, const char **ccname)
         DEBUG(1, ("stat failed [%d][%s].\n", errno, strerror(errno)));
         return errno;
     } else if (ret == -1 &&  errno == ENOENT) {
-        *ccname = NULL;
         return EOK;
     }
 
@@ -165,17 +167,11 @@ static errno_t check_if_ccache_file_is_used(uid_t uid, const char **ccname)
     }
 
     if (!active) {
-        DEBUG(5, ("User [%d] is not active, deleting old ccache file [%s].\n",
-                  uid, filename));
-        ret = unlink(filename);
-        if (ret == -1) {
-            DEBUG(1, ("unlink failed [%d][%s].\n", errno, strerror(errno)));
-            return errno;
-        }
-        *ccname = NULL;
+        DEBUG(5, ("User [%d] is not active\n", uid));
     } else {
         DEBUG(9, ("User [%d] is still active, reusing ccache file [%s].\n",
                   uid, filename));
+        *result = true;
     }
     return EOK;
 }
@@ -734,12 +730,13 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res)
     struct krb5_ctx *krb5_ctx;
     struct krb5child_req *kr = NULL;
     struct tevent_req *req;
+    krb5_error_code kerr;
     int ret;
     struct pam_data *pd;
     int pam_status=PAM_SYSTEM_ERR;
     int dp_err = DP_ERR_FATAL;
     const char *ccache_file = NULL;
-    const char *dummy;
+    const char *realm;
 
     ret = krb5_setup(be_req, &kr);
     if (ret != EOK) {
@@ -755,6 +752,12 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res)
         goto failed;
     }
 
+    realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
+    if (realm == NULL) {
+        DEBUG(1, ("Missing Kerberos realm.\n"));
+        goto failed;
+    }
+
     switch (res->count) {
     case 0:
         DEBUG(5, ("No attributes for user [%s] found.\n", pd->user));
@@ -765,19 +768,12 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res)
         pd->upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL);
         if (pd->upn == NULL) {
             /* NOTE: this is a hack, works only in some environments */
-            dummy = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
-            if (dummy != NULL) {
-                pd->upn = talloc_asprintf(be_req, "%s@%s", pd->user, dummy);
-                if (pd->upn == NULL) {
-                    DEBUG(1, ("failed to build simple upn.\n"));
-                }
-                DEBUG(9, ("Using simple UPN [%s].\n", pd->upn));
+            pd->upn = talloc_asprintf(be_req, "%s@%s", pd->user, realm);
+            if (pd->upn == NULL) {
+                DEBUG(1, ("failed to build simple upn.\n"));
+                goto failed;
             }
-        }
-
-        if (pd->upn == NULL) {
-            DEBUG(1, ("Cannot set UPN.\n"));
-            goto failed;
+            DEBUG(9, ("Using simple UPN [%s].\n", pd->upn));
         }
 
         kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR,
@@ -790,31 +786,28 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res)
                                                   SYSDB_CCACHE_FILE,
                                                   NULL);
         if (ccache_file != NULL) {
-            ret = check_if_ccache_file_is_used(pd->pw_uid, &ccache_file);
+            ret = check_if_ccache_file_is_used(pd->pw_uid, ccache_file,
+                                               &kr->active_ccache_present);
             if (ret != EOK) {
                 DEBUG(1, ("check_if_ccache_file_is_used failed.\n"));
                 goto failed;
             }
-        }
 
-        if (ccache_file == NULL) {
-            kr->active_ccache_present = false;
-            DEBUG(4, ("No active ccache file for user [%s] found.\n",
-                      pd->user));
-            ccache_file = expand_ccname_template(kr, kr,
-                                          dp_opt_get_cstring(kr->krb5_ctx->opts,
-                                                             KRB5_CCNAME_TMPL)
-                                    );
-            if (ccache_file == NULL) {
-                DEBUG(1, ("expand_ccname_template failed.\n"));
+            kerr = check_for_valid_tgt(ccache_file, realm, pd->upn,
+                                       &kr->valid_tgt_present);
+            if (kerr != 0) {
+                DEBUG(1, ("check_for_valid_tgt failed.\n"));
                 goto failed;
             }
         } else {
-            kr->active_ccache_present = true;
+            kr->active_ccache_present = false;
+            kr->valid_tgt_present = false;
+            DEBUG(4, ("No ccache file for user [%s] found.\n", pd->user));
         }
-        DEBUG(9, ("Ccache_file is [%s] and %s.\n", ccache_file,
-                  kr->active_ccache_present ? "will be kept/renewed" :
-                                              "will be generated"));
+        DEBUG(9, ("Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
+                  ccache_file ? ccache_file : "not set",
+                  kr->active_ccache_present ? "" : "not",
+                  kr->valid_tgt_present ? "" : "not"));
         kr->ccname = ccache_file;
         break;
 
@@ -852,6 +845,8 @@ static void krb5_resolve_done(struct tevent_req *req)
     int dp_err = DP_ERR_FATAL;
     struct pam_data *pd = kr->pd;
     struct be_req *be_req = kr->req;
+    char *msg;
+    size_t offset = 0;
 
     ret = be_resolve_server_recv(req, &kr->srv);
     talloc_zfree(req);
@@ -864,9 +859,59 @@ static void krb5_resolve_done(struct tevent_req *req)
         kr->is_offline = true;
     }
 
+    if (kr->ccname == NULL ||
+        (be_is_offline(be_req->be_ctx) && !kr->active_ccache_present &&
+            !kr->valid_tgt_present) ||
+        (!be_is_offline(be_req->be_ctx) && !kr->active_ccache_present)) {
+            DEBUG(9, ("Recreating  ccache file.\n"));
+            if (kr->ccname != NULL) {
+                if (strncmp(kr->ccname, "FILE:", 5) == 0) {
+                    offset = 5;
+                }
+                if (kr->ccname[offset] != '/') {
+                    DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n",
+                              kr->ccname + offset));
+                    goto done;
+                }
+                ret = unlink(kr->ccname + offset);
+                if (ret == -1 && errno != ENOENT) {
+                    DEBUG(1, ("unlink [%s] failed [%d][%s].\n", kr->ccname,
+                             errno, strerror(errno)));
+                    goto done;
+                }
+            }
+            kr->ccname = expand_ccname_template(kr, kr,
+                                          dp_opt_get_cstring(kr->krb5_ctx->opts,
+                                                             KRB5_CCNAME_TMPL)
+                                    );
+            if (kr->ccname == NULL) {
+                DEBUG(1, ("expand_ccname_template failed.\n"));
+                goto done;
+            }
+    }
+
     if (be_is_offline(be_req->be_ctx)) {
         DEBUG(9, ("Preparing for offline operation.\n"));
         kr->is_offline = true;
+
+        if (kr->valid_tgt_present) {
+            DEBUG(9, ("Valid TGT available, nothing to do.\n"));
+            msg = talloc_asprintf(pd, "%s=%s", CCACHE_ENV_NAME, kr->ccname);
+            if (msg == NULL) {
+                DEBUG(1, ("talloc_asprintf failed.\n"));
+                goto done;
+            }
+
+            ret = pam_add_response(pd, PAM_ENV_ITEM, strlen(msg) + 1,
+                                   (uint8_t *) msg);
+            if (ret != EOK) {
+                DEBUG(1, ("pam_add_response failed.\n"));
+            }
+
+            pam_status = PAM_SUCCESS;
+            dp_err = DP_ERR_OFFLINE;
+            goto done;
+        }
         memset(pd->authtok, 0, pd->authtok_size);
         pd->authtok_size = 0;
 
diff --git a/server/providers/krb5/krb5_auth.h b/server/providers/krb5/krb5_auth.h
index f222c7b..a011af8 100644
--- a/server/providers/krb5/krb5_auth.h
+++ b/server/providers/krb5/krb5_auth.h
@@ -51,6 +51,7 @@ struct krb5child_req {
     bool is_offline;
     struct fo_server *srv;
     bool active_ccache_present;
+    bool valid_tgt_present;
 };
 
 struct fo_service;
diff --git a/server/util/sss_krb5.c b/server/util/sss_krb5.c
index e96e1ba..0bc25df 100644
--- a/server/util/sss_krb5.c
+++ b/server/util/sss_krb5.c
@@ -19,9 +19,11 @@
 */
 #include <stdio.h>
 #include <errno.h>
+#include <talloc.h>
 
 #include "config.h"
 
+#include "util/util.h"
 #include "util/sss_krb5.h"
 
 
@@ -102,3 +104,93 @@ void KRB5_CALLCONV sss_krb5_free_unparsed_name(krb5_context context, char *name)
     }
 #endif
 }
+
+
+krb5_error_code check_for_valid_tgt(const char *ccname, const char *realm,
+                                    const char *client_princ_str, bool *result)
+{
+    krb5_context context = NULL;
+    krb5_ccache ccache = NULL;
+    krb5_error_code krberr;
+    TALLOC_CTX *tmp_ctx = NULL;
+    krb5_creds mcred;
+    krb5_creds cred;
+    char *server_name = NULL;
+    krb5_principal client_principal = NULL;
+    krb5_principal server_principal = NULL;
+
+    *result = false;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(1, ("talloc_new failed.\n"));
+        return ENOMEM;
+    }
+
+    krberr = krb5_init_context(&context);
+    if (krberr) {
+        DEBUG(1, ("Failed to init kerberos context\n"));
+        goto done;
+    }
+
+    krberr = krb5_cc_resolve(context, ccname, &ccache);
+    if (krberr != 0) {
+        DEBUG(1, ("krb5_cc_resolve failed.\n"));
+        goto done;
+    }
+
+    server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
+    if (server_name == NULL) {
+        DEBUG(1, ("talloc_asprintf failed.\n"));
+        goto done;
+    }
+
+    krberr = krb5_parse_name(context, server_name, &server_principal);
+    if (krberr != 0) {
+        DEBUG(1, ("krb5_parse_name failed.\n"));
+        goto done;
+    }
+
+    krberr = krb5_parse_name(context, client_princ_str, &client_principal);
+    if (krberr != 0) {
+        DEBUG(1, ("krb5_parse_name failed.\n"));
+        goto done;
+    }
+
+    memset(&mcred, 0, sizeof(mcred));
+    memset(&cred, 0, sizeof(mcred));
+    mcred.client = client_principal;
+    mcred.server = server_principal;
+
+    krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
+    if (krberr != 0) {
+        DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
+        krberr = 0;
+        goto done;
+    }
+
+    DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
+
+    if (cred.times.endtime > time(NULL)) {
+        DEBUG(3, ("TGT is valid.\n"));
+        *result = true;
+    }
+    krb5_free_cred_contents(context, &cred);
+
+    krberr = 0;
+
+done:
+    if (client_principal != NULL) {
+        krb5_free_principal(context, client_principal);
+    }
+    if (server_principal != NULL) {
+        krb5_free_principal(context, server_principal);
+    }
+    if (ccache != NULL) {
+        krb5_cc_close(context, ccache);
+    }
+    if (context != NULL) krb5_free_context(context);
+    talloc_free(tmp_ctx);
+    return krberr;
+}
+
diff --git a/server/util/sss_krb5.h b/server/util/sss_krb5.h
index 342196d..60994e1 100644
--- a/server/util/sss_krb5.h
+++ b/server/util/sss_krb5.h
@@ -44,4 +44,7 @@ void KRB5_CALLCONV sss_krb5_get_init_creds_opt_free (krb5_context context,
                                                   krb5_get_init_creds_opt *opt);
 
 void KRB5_CALLCONV sss_krb5_free_unparsed_name(krb5_context context, char *name);
+
+krb5_error_code check_for_valid_tgt(const char *ccname, const char *realm,
+                                    const char *client_princ_str, bool *result);
 #endif /* __SSS_KRB5_H__ */
-- 
1.6.5.2



More information about the sssd-devel mailing list