diff options
-rw-r--r-- | source3/include/ads.h | 1 | ||||
-rw-r--r-- | source3/include/proto.h | 2 | ||||
-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 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 2 | ||||
-rw-r--r-- | source3/libsmb/clispnego.c | 4 | ||||
-rw-r--r-- | source3/winbindd/winbindd_ads.c | 6 |
8 files changed, 102 insertions, 14 deletions
diff --git a/source3/include/ads.h b/source3/include/ads.h index 91a0f8162f..3de1d8b199 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -45,6 +45,7 @@ typedef struct ads_struct { char *kdc_server; unsigned flags; int time_offset; + char *ccache_name; time_t tgt_expire; time_t tgs_expire; time_t renewable; diff --git a/source3/include/proto.h b/source3/include/proto.h index 6dbdf4eae1..b3fa55a914 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -768,7 +768,7 @@ int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx, const char *principal, int time_offset, DATA_BLOB *targ, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, - time_t *expire_time); + const char *ccname, time_t *expire_time); bool spnego_parse_challenge(TALLOC_CTX *ctx, const DATA_BLOB blob, DATA_BLOB *chal1, DATA_BLOB *chal2); DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob); 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); diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index b74faa6fd9..9ce013ee64 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -1461,7 +1461,7 @@ static struct tevent_req *cli_session_setup_kerberos_send( * we have to acquire a ticket. To be fixed later :-) */ rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg, - &state->session_key_krb5, 0, NULL); + &state->session_key_krb5, 0, NULL, NULL); if (rc) { DEBUG(1, ("cli_session_setup_kerberos: " "spnego_gen_krb5_negTokenInit failed: %s\n", diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index 81f9dfb20c..a17efbf75b 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -255,7 +255,7 @@ int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx, const char *principal, int time_offset, DATA_BLOB *targ, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, - time_t *expire_time) + const char *ccname, time_t *expire_time) { int retval; DATA_BLOB tkt, tkt_wrapped; @@ -264,7 +264,7 @@ int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx, /* get a kerberos ticket for the service and extract the session key */ retval = cli_krb5_get_ticket(ctx, principal, time_offset, &tkt, session_key_krb5, - extra_ap_opts, NULL, + extra_ap_opts, ccname, expire_time, NULL); if (retval) { return retval; diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 4efd829cb9..628fd1c3f2 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -78,15 +78,15 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) } } - /* we don't want this to affect the users ccache */ - setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1); - ads = ads_init(domain->alt_name, domain->name, NULL); if (!ads) { DEBUG(1,("ads_init for domain %s failed\n", domain->name)); return NULL; } + /* we don't want ads operations to affect the default ccache */ + ads->auth.ccache_name = SMB_STRDUP("MEMORY:winbind_ccache"); + /* the machine acct password might have change - fetch it every time */ SAFE_FREE(ads->auth.password); |