summaryrefslogtreecommitdiff
path: root/source3/libads
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2012-09-07 14:14:08 -0400
committerAlexander Bokovoy <ab@samba.org>2012-09-12 21:18:09 +0200
commit893b21387665a7b644355d60f6fbccaf48ffaedb (patch)
tree91721ee23469a110630937c14efbdc2b62ae5412 /source3/libads
parenta11e45f1c5268e798124fe9e0716b7b9d0557014 (diff)
downloadsamba-893b21387665a7b644355d60f6fbccaf48ffaedb.tar.gz
samba-893b21387665a7b644355d60f6fbccaf48ffaedb.tar.bz2
samba-893b21387665a7b644355d60f6fbccaf48ffaedb.zip
Avoid overriding default ccache for ads operations.
Avoid overriding default ccache for ads operations. Nowadays various samba components may need to use GSSAPI and a default cred cache to perform their tasks. This code was completely overriding the whole process default ccache name, thus altering the current credentials and sometimes hijacking them (or getting preemptively hijaked). By using gss_krb5_import_cred we can instead use a private ccache (necessary sometimes to use a different set of credentials fromt he default cifs/fqdn@realm one, for example when contacting foreign DCs using trust credentials) that does not affect the rest of the process. For the kerberos versions which don't have gss_krb5_import_cred we fallback to temp override of KRB5CCNAME and gss_acquire_cred. Signed-off-by: Alexander Bokovoy <ab@samba.org> Signed-off-by: Günther Deschner <gd@samba.org> Autobuild-User(master): Alexander Bokovoy <ab@samba.org> Autobuild-Date(master): Wed Sep 12 21:18:09 CEST 2012 on sn-devel-104
Diffstat (limited to 'source3/libads')
-rw-r--r--source3/libads/ads_struct.c1
-rw-r--r--source3/libads/kerberos_util.c8
-rw-r--r--source3/libads/sasl.c92
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);