From 5c075562ac687f7102c7c940fec2e82da378bfff Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 26 Aug 2014 09:43:09 +0200 Subject: 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. Reviewed-by: Sumit Bose --- src/providers/ldap/ldap_child.c | 44 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c index d0552d57c..6ef7bd204 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; @@ -185,6 +187,8 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, int kdc_time_offset_usec; int ret; TALLOC_CTX *tmp_ctx; + char *ccname_file_dummy; + char *ccname_file; krberr = krb5_init_context(&context); if (krberr) { @@ -290,14 +294,34 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, goto done; } - ccname = talloc_asprintf(tmp_ctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); - if (!ccname) { - krberr = KRB5KRB_ERR_GENERIC; + ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX", + DB_PATH, realm_name); + ccname_file = talloc_asprintf(tmp_ctx, "%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(tmp_ctx, "FILE:%s", ccname_file_dummy); + ccname = talloc_asprintf(tmp_ctx, "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)); @@ -368,6 +392,16 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, kdc_time_offset = 0; #endif + DEBUG(SSSDBG_TRACE_INTERNAL, + "Renaming [%s] to [%s]\n", ccname_file_dummy, ccname_file); + 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 = talloc_steal(memctx, ccname); *expire_time_out = my_creds.times.endtime - kdc_time_offset; -- cgit