#define DBGC_CLASS DBGC_AUTH
static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred);
-static void cli_credentials_invalidate_client_gss_creds(
- struct cli_credentials *cred,
- enum credentials_obtained obtained);
/* Free a memory ccache */
static int free_mccache(struct ccache_container *ccc)
return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
}
-/* We have good reason to think the ccache in these credentials is invalid - blow it away */
-static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
-{
- if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
- talloc_unlink(cred, cred->client_gss_creds);
- cred->client_gss_creds = NULL;
- }
- cred->client_gss_creds_obtained = CRED_UNINITIALISED;
-}
-
-void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred,
- enum credentials_obtained obtained)
-{
- /* If the caller just changed the username/password etc, then
- * any cached credentials are now invalid */
- if (obtained >= cred->client_gss_creds_obtained) {
- if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
- talloc_unlink(cred, cred->client_gss_creds);
- cred->client_gss_creds = NULL;
- }
- cred->client_gss_creds_obtained = CRED_UNINITIALISED;
- }
- /* Now that we know that the data is 'this specified', then
- * don't allow something less 'known' to be returned as a
- * ccache. Ie, if the username is on the command line, we
- * don't want to later guess to use a file-based ccache */
- if (obtained > cred->client_gss_creds_threshold) {
- cred->client_gss_creds_threshold = obtained;
- }
-}
-
/* We have good reason to think this CCACHE is invalid. Blow it away */
static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred)
{
cred->ccache = NULL;
}
cred->ccache_obtained = CRED_UNINITIALISED;
-
- cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
}
_PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred,
if (obtained > cred->ccache_threshold) {
cred->ccache_threshold = obtained;
}
-
- cli_credentials_invalidate_client_gss_creds(cred,
- obtained);
}
static int free_gssapi_creds(struct gssapi_creds_container *gcc)
return 0;
}
-_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
- struct tevent_context *event_ctx,
- struct loadparm_context *lp_ctx,
- struct gssapi_creds_container **_gcc,
- const char **error_string)
-{
- int ret = 0;
- OM_uint32 maj_stat, min_stat;
- struct gssapi_creds_container *gcc;
- struct ccache_container *ccache;
-#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
- gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
- gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
-#endif
- krb5_enctype *etypes = NULL;
-
- if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold &&
- cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
- bool expired = false;
- OM_uint32 lifetime = 0;
- gss_cred_usage_t usage = 0;
- maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds,
- NULL, &lifetime, &usage, NULL);
- if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) {
- DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred)));
- expired = true;
- } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) {
- DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime));
- expired = true;
- } else if (maj_stat != GSS_S_COMPLETE) {
- *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
- gssapi_error_string(cred, maj_stat, min_stat, NULL));
- return EINVAL;
- }
- if (expired) {
- cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
- } else {
- DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
- cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
-
- *_gcc = cred->client_gss_creds;
- return 0;
- }
- }
-
- ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
- &ccache, error_string);
- if (ret) {
- if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
- DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string));
- } else {
- DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string));
- }
- return ret;
- }
-
- gcc = talloc(cred, struct gssapi_creds_container);
- if (!gcc) {
- (*error_string) = error_message(ENOMEM);
- return ENOMEM;
- }
-
- maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
- ccache->ccache, NULL, NULL,
- &gcc->creds);
- if ((maj_stat == GSS_S_FAILURE) &&
- (min_stat == (OM_uint32)KRB5_CC_END ||
- min_stat == (OM_uint32)KRB5_CC_NOTFOUND ||
- min_stat == (OM_uint32)KRB5_FCC_NOFILE))
- {
- /* This CCACHE is no good. Ensure we don't use it again */
- cli_credentials_unconditionally_invalidate_ccache(cred);
-
- /* Now try again to get a ccache */
- ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
- &ccache, error_string);
- if (ret) {
- DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
- return ret;
- }
-
- maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
- ccache->ccache, NULL, NULL,
- &gcc->creds);
-
- }
-
- if (maj_stat) {
- talloc_free(gcc);
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- (*error_string) = talloc_asprintf(cred, "smb_gss_krb5_import_cred failed: %s", error_message(ret));
- return ret;
- }
-
-
- /*
- * transfer the enctypes from the smb_krb5_context to the gssapi layer
- *
- * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
- * to configure the enctypes via the krb5.conf.
- *
- * And the gss_init_sec_context() creates it's own krb5_context and
- * the TGS-REQ had all enctypes in it and only the ones configured
- * and used for the AS-REQ, so it wasn't possible to disable the usage
- * of AES keys.
- */
- min_stat = smb_krb5_get_allowed_etypes(ccache->smb_krb5_context->krb5_context,
- &etypes);
- if (min_stat == 0) {
- OM_uint32 num_ktypes;
-
- for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
-
- maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
- num_ktypes,
- (int32_t *) etypes);
- SAFE_FREE(etypes);
- if (maj_stat) {
- talloc_free(gcc);
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
- return ret;
- }
- }
-
-#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
- /*
- * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
- *
- * This allows us to disable SIGN and SEAL on a TLS connection with
- * GSS-SPNENO. For example ldaps:// connections.
- *
- * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
- * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
- */
- maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
- oid,
- &empty_buffer);
- if (maj_stat) {
- talloc_free(gcc);
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
- return ret;
- }
-#endif
- cred->client_gss_creds_obtained = cred->ccache_obtained;
- cred->client_gss_creds_threshold = cred->ccache_obtained;
- talloc_set_destructor(gcc, free_gssapi_creds);
- cred->client_gss_creds = gcc;
- *_gcc = gcc;
- return 0;
-}
-
/**
Set a gssapi cred_id_t into the credentials system. (Client case)
int ret;
OM_uint32 maj_stat, min_stat;
struct ccache_container *ccc = NULL;
- struct gssapi_creds_container *gcc = NULL;
- if (cred->client_gss_creds_obtained > obtained) {
- return 0;
- }
- gcc = talloc(cred, struct gssapi_creds_container);
- if (!gcc) {
- (*error_string) = error_message(ENOMEM);
- return ENOMEM;
+ if (cred->ccache_obtained > obtained) {
+ return 0;
}
ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string);
if (ret == 0) {
ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
}
- if (ret == 0) {
- gcc->creds = gssapi_cred;
- talloc_set_destructor(gcc, free_gssapi_creds);
-
- /* set the clinet_gss_creds_obtained here, as it just
- got set to UNINITIALISED by the calls above */
- cred->client_gss_creds_obtained = obtained;
- cred->client_gss_creds_threshold = obtained;
- cred->client_gss_creds = gcc;
- }
+
return ret;
}
}
cred->ccache = ccc;
- cred->client_gss_creds = NULL;
- cred->client_gss_creds_obtained = CRED_UNINITIALISED;
- cred->client_gss_creds_threshold = CRED_UNINITIALISED;
return ret;
}