summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/ads.h1
-rw-r--r--source3/include/proto.h2
-rw-r--r--source3/libads/ads_struct.c1
-rw-r--r--source3/libads/kerberos_util.c8
-rw-r--r--source3/libads/sasl.c92
-rw-r--r--source3/libsmb/cliconnect.c2
-rw-r--r--source3/libsmb/clispnego.c4
-rw-r--r--source3/winbindd/winbindd_ads.c6
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);