auth: added cli_credentials_failed_kerberos_login()
authorAndrew Tridgell <tridge@samba.org>
Wed, 31 Oct 2012 06:58:20 +0000 (17:58 +1100)
committerAndrew Tridgell <tridge@samba.org>
Thu, 1 Nov 2012 04:40:40 +0000 (15:40 +1100)
this is used to support retrying kerberos connections after removing a
ccache entry, to cope with a server being re-built while our client
still has a valid service ticket

Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>

auth/credentials/credentials.h
auth/credentials/credentials_krb5.c

index 0bcfd61264d2668629c1ddcfde81a9aafe54bdbe..dbc014fd08ce3529390a91d22186313118b6d184 100644 (file)
@@ -182,6 +182,9 @@ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
                                     struct loadparm_context *lp_ctx,
                                     char *ccache_name,
                                     struct ccache_container **ccc, const char **error_string);
+bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred,
+                                          const char *principal,
+                                          unsigned int *count);
 int cli_credentials_get_keytab(struct cli_credentials *cred, 
                               struct loadparm_context *lp_ctx,
                               struct keytab_container **_ktc);
index 459e9487f4822cf8f37d52ab98e7a6d4acbf23e8..cc51f56d79b2a0f0d7027491bc766ecbca258792 100644 (file)
@@ -212,6 +212,67 @@ _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
        return 0;
 }
 
+/*
+ * Indicate the we failed to log in to this service/host with these
+ * credentials.  The caller passes an unsigned int which they
+ * initialise to the number of times they would like to retry.
+ *
+ * This method is used to support re-trying with freshly fetched
+ * credentials in case a server is rebuilt while clients have
+ * non-expired tickets. When the client code gets a logon failure they
+ * throw away the existing credentials for the server and retry.
+ */
+_PUBLIC_ bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred,
+                                                   const char *principal,
+                                                   unsigned int *count)
+{
+       struct ccache_container *ccc;
+       krb5_creds creds, creds2;
+       int ret;
+
+       if (principal == NULL) {
+               /* no way to delete if we don't know the principal */
+               return false;
+       }
+
+       ccc = cred->ccache;
+       if (ccc == NULL) {
+               /* not a kerberos connection */
+               return false;
+       }
+
+       if (*count > 0) {
+               /* We have already tried discarding the credentials */
+               return false;
+       }
+       (*count)++;
+
+       ZERO_STRUCT(creds);
+       ret = krb5_parse_name(ccc->smb_krb5_context->krb5_context, principal, &creds.server);
+       if (ret != 0) {
+               return false;
+       }
+
+       ret = krb5_cc_retrieve_cred(ccc->smb_krb5_context->krb5_context, ccc->ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &creds, &creds2);
+       if (ret != 0) {
+               /* don't retry - we didn't find these credentials to remove */
+               return false;
+       }
+
+       ret = krb5_cc_remove_cred(ccc->smb_krb5_context->krb5_context, ccc->ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &creds);
+       krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context, &creds2);
+       if (ret != 0) {
+               /* don't retry - we didn't find these credentials to
+                * remove. Note that with the current backend this
+                * never happens, as it always returns 0 even if the
+                * creds don't exist, which is why we do a separate
+                * krb5_cc_retrieve_cred() above.
+                */
+               return false;
+       }
+       return true;
+}
+
 
 static int cli_credentials_new_ccache(struct cli_credentials *cred, 
                                      struct loadparm_context *lp_ctx,