diff options
Diffstat (limited to 'source3/libads')
-rw-r--r-- | source3/libads/ads_struct.c | 1 | ||||
-rw-r--r-- | source3/libads/kerberos_util.c | 8 | ||||
-rw-r--r-- | source3/libads/sasl.c | 92 |
3 files changed, 94 insertions, 7 deletions
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index 45d00a39a3..fd7e417bad 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -201,6 +201,7 @@ void ads_destroy(ADS_STRUCT **ads) SAFE_FREE((*ads)->auth.password); SAFE_FREE((*ads)->auth.user_name); SAFE_FREE((*ads)->auth.kdc_server); + SAFE_FREE((*ads)->auth.ccache_name); SAFE_FREE((*ads)->config.realm); SAFE_FREE((*ads)->config.bind_path); diff --git a/source3/libads/kerberos_util.c b/source3/libads/kerberos_util.c index 7d49c02869..645b058262 100644 --- a/source3/libads/kerberos_util.c +++ b/source3/libads/kerberos_util.c @@ -63,9 +63,11 @@ int ads_kinit_password(ADS_STRUCT *ads) return KRB5_LIBOS_CANTREADPWD; } - ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset, - &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable, - NULL); + ret = kerberos_kinit_password_ext(s, ads->auth.password, + ads->auth.time_offset, + &ads->auth.tgt_expire, NULL, + ads->auth.ccache_name, false, false, + ads->auth.renewable, NULL); if (ret) { DEBUG(0,("kerberos_kinit_password %s failed: %s\n", diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c index 438db05df8..33f4e24191 100644 --- a/source3/libads/sasl.c +++ b/source3/libads/sasl.c @@ -271,6 +271,74 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) } #ifdef HAVE_KRB5 +static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred) +{ + ADS_STATUS status; + krb5_context kctx; + krb5_error_code kerr; + krb5_ccache kccache = NULL; + uint32_t maj, min; + + *cred = GSS_C_NO_CREDENTIAL; + + if (!ads->auth.ccache_name) { + return ADS_SUCCESS; + } + + kerr = krb5_init_context(&kctx); + if (kerr) { + return ADS_ERROR_KRB5(kerr); + } + +#ifdef HAVE_GSS_KRB5_IMPORT_CRED + kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache); + if (kerr) { + status = ADS_ERROR_KRB5(kerr); + goto done; + } + + maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred); + if (maj != GSS_S_COMPLETE) { + status = ADS_ERROR_GSS(maj, min); + goto done; + } +#else + /* We need to fallback to overriding the default creds. + * This operation is not thread safe as it changes the process + * environment variable, but we do not have any better option + * with older kerberos libraries */ + { + const char *oldccname = NULL; + + oldccname = getenv("KRB5CCNAME"); + setenv("KRB5CCNAME", ads->auth.ccache_name, 1); + + maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE, + NULL, GSS_C_INITIATE, cred, NULL, NULL); + + if (oldccname) { + setenv("KRB5CCNAME", oldccname, 1); + } else { + unsetenv("KRB5CCNAME"); + } + + if (maj != GSS_S_COMPLETE) { + status = ADS_ERROR_GSS(maj, min); + goto done; + } + } +#endif + + status = ADS_SUCCESS; + +done: + if (!ADS_ERR_OK(status) && kccache != NULL) { + krb5_cc_close(kctx, kccache); + } + krb5_free_context(kctx); + return status; +} + static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len) { gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data; @@ -377,6 +445,7 @@ static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t bool ok; uint32 minor_status; int gss_rc, rc; + gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; gss_OID_desc krb5_mech_type = {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }; gss_OID mech_type = &krb5_mech_type; @@ -390,6 +459,11 @@ static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t DATA_BLOB wrapped; struct berval cred, *scred = NULL; + status = ads_init_gssapi_cred(ads, &gss_cred); + if (!ADS_ERR_OK(status)) { + goto failed; + } + input_token.value = NULL; input_token.length = 0; @@ -407,7 +481,7 @@ static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t /* Note: here we explicit ask for the krb5 mech_type */ gss_rc = gss_init_sec_context(&minor_status, - GSS_C_NO_CREDENTIAL, + gss_cred, &context_handle, serv_name, mech_type, @@ -544,7 +618,7 @@ static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t * to gssapi */ gss_rc = gss_init_sec_context(&minor_status, - GSS_C_NO_CREDENTIAL, + gss_cred, &context_handle, serv_name, mech_type, @@ -606,6 +680,8 @@ static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t status = ADS_SUCCESS; failed: + if (gss_cred != GSS_C_NO_CREDENTIAL) + gss_release_cred(&minor_status, &gss_cred); if (context_handle != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); return status; @@ -791,6 +867,7 @@ static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *prin rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal, ads->auth.time_offset, &blob, &session_key, 0, + ads->auth.ccache_name, &ads->auth.tgs_expire); if (rc) { @@ -952,6 +1029,7 @@ failed: static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name) { uint32 minor_status; + gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; gss_OID mech_type = GSS_C_NULL_OID; gss_buffer_desc output_token, input_token; @@ -969,6 +1047,11 @@ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv input_token.value = NULL; input_token.length = 0; + status = ads_init_gssapi_cred(ads, &gss_cred); + if (!ADS_ERR_OK(status)) { + goto failed; + } + /* * Note: here we always ask the gssapi for sign and seal * as this is negotiated later after the mutal @@ -978,7 +1061,7 @@ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv for (i=0; i < MAX_GSS_PASSES; i++) { gss_rc = gss_init_sec_context(&minor_status, - GSS_C_NO_CREDENTIAL, + gss_cred, &context_handle, serv_name, mech_type, @@ -1137,7 +1220,8 @@ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv } failed: - + if (gss_cred != GSS_C_NO_CREDENTIAL) + gss_release_cred(&minor_status, &gss_cred); if (context_handle != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); |