>From 58347c89c9d2ee788e0f6ccf6becc44537423d0e Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 26 Aug 2014 09:43:09 +0200 Subject: [PATCH] LDAP: Use randomized ccname for storing credentials https://fedorahosted.org/sssd/ticket/2410 If two ldap_child processes attempt to prime the ccache at the same time for the same domain, the ldap_child might fail with: [ldap_child_get_tgt_sync] (0x0040): Failed to init ccache: Internal credentials cache error [main] (0x0020): ldap_child_get_tgt_sync failed. To avoid the race-condition, the ldap_child process now creates the ccache randomized and before returning to the caller, renames the randomized ccache to a permanent one. --- src/providers/ldap/ldap_child.c | 42 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c index e2fe3f232b3f051bf1d94617c2c711b7087130c7..677d61792b867cf489598f67fb8a61e0bace1cfa 100644 --- a/src/providers/ldap/ldap_child.c +++ b/src/providers/ldap/ldap_child.c @@ -168,7 +168,9 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, const char **ccname_out, time_t *expire_time_out) { + int fd; char *ccname; + char *ccname_dummy; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; @@ -184,6 +186,8 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, int canonicalize = 0; int kdc_time_offset_usec; int ret; + char *ccname_file_dummy; + char *ccname_file; krberr = krb5_init_context(&context); if (krberr) { @@ -283,14 +287,34 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, goto done; } - ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); - if (!ccname) { - krberr = KRB5KRB_ERR_GENERIC; + ccname_file_dummy = talloc_asprintf(memctx, "%s/ccache_%s_XXXXXX", + DB_PATH, realm_name); + ccname_file = talloc_asprintf(memctx, "%s/ccache_%s", + DB_PATH, realm_name); + if (ccname_file_dummy == NULL || ccname_file == NULL) { + ret = ENOMEM; goto done; } - DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname); - krberr = krb5_cc_resolve(context, ccname, &ccache); + fd = mkstemp(ccname_file_dummy); + if (fd == -1) { + ret = errno; + goto done; + } + /* We only care about creating a unique file name here, we don't + * need the fd + */ + close(fd); + + ccname_dummy = talloc_asprintf(memctx, "FILE:%s", ccname_file_dummy); + ccname = talloc_asprintf(memctx, "FILE:%s", ccname_file); + if (ccname_dummy == NULL || ccname == NULL) { + krberr = ENOMEM; + goto done; + } + DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy); + + krberr = krb5_cc_resolve(context, ccname_dummy, &ccache); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr)); @@ -361,6 +385,14 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, kdc_time_offset = 0; #endif + ret = rename(ccname_file_dummy, ccname_file); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "rename failed [%d][%s].\n", ret, strerror(ret)); + goto done; + } + krberr = 0; *ccname_out = ccname; *expire_time_out = my_creds.times.endtime - kdc_time_offset; -- 1.9.3