summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2007-02-08 17:09:56 +0000
committerGünther Deschner <gd@samba.org>2007-02-08 17:09:56 +0000
commit88f0dae580a2ddb3259d7e79db1a4b0ef518dab7 (patch)
tree37152ee6945b2fd4fd8147fdd42d801df226d532
parent070d60e711bee3409237e8ca64c08a54ba169bdb (diff)
downloadsamba-88f0dae580a2ddb3259d7e79db1a4b0ef518dab7.tar.gz
samba-88f0dae580a2ddb3259d7e79db1a4b0ef518dab7.tar.xz
samba-88f0dae580a2ddb3259d7e79db1a4b0ef518dab7.zip
r21241: Merge from 3_0:
Fix longstanding Bug #4009. For the winbind cached ADS LDAP connection handling (ads_cached_connection()) we were (incorrectly) assuming that the service ticket lifetime equaled the tgt lifetime. For setups where the service ticket just lives 10 minutes, we were leaving hundreds of LDAP connections in CLOSE_WAIT state, until we fail to service entirely with "Too many open files". Also sequence_number() in winbindd_ads.c needs to delete the cached LDAP connection after the ads_do_search_retry() has failed to submit the search request (although the bind succeeded (returning an expired service ticket that we cannot delete from the memory cred cache - this will get fixed later)). Guenther
-rw-r--r--source/include/ads.h3
-rw-r--r--source/include/includes.h2
-rw-r--r--source/libads/kerberos.c6
-rw-r--r--source/libads/ldap_utils.c4
-rw-r--r--source/libads/sasl.c8
-rw-r--r--source/libsmb/cliconnect.c2
-rw-r--r--source/libsmb/clikrb5.c20
-rw-r--r--source/libsmb/clispnego.c6
-rw-r--r--source/nsswitch/idmap_ad.c13
-rw-r--r--source/nsswitch/winbindd_ads.c32
-rw-r--r--source/nsswitch/winbindd_pam.c3
-rw-r--r--source/rpc_client/cli_pipe.c2
-rw-r--r--source/utils/ntlm_auth.c4
13 files changed, 72 insertions, 33 deletions
diff --git a/source/include/ads.h b/source/include/ads.h
index d97ae1531f9..29df0d2f353 100644
--- a/source/include/ads.h
+++ b/source/include/ads.h
@@ -42,7 +42,8 @@ typedef struct {
char *kdc_server;
unsigned flags;
int time_offset;
- time_t expire;
+ time_t tgt_expire;
+ time_t tgs_expire;
time_t renewable;
} auth;
diff --git a/source/include/includes.h b/source/include/includes.h
index d419529986f..7a6064d8264 100644
--- a/source/include/includes.h
+++ b/source/include/includes.h
@@ -1167,7 +1167,7 @@ BOOL smb_krb5_principal_compare_any_realm(krb5_context context,
krb5_const_principal princ1,
krb5_const_principal princ2);
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
- DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, const char *ccname);
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, const char *ccname, time_t *tgs_expire);
PAC_LOGON_INFO *get_logon_info_from_pac(PAC_DATA *pac_data);
krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, const char *client_string, const char *service_string, time_t *new_start_time);
krb5_error_code kpasswd_err_to_krb5_err(krb5_error_code res_code);
diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c
index 92461bd9c1e..8e8297b07e5 100644
--- a/source/libads/kerberos.c
+++ b/source/libads/kerberos.c
@@ -110,6 +110,10 @@ int kerberos_kinit_password_ext(const char *principal,
krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
krb5_get_init_creds_opt_set_forwardable(opt, True);
+#if 0
+ /* insane testing */
+ krb5_get_init_creds_opt_set_tkt_life(opt, 60);
+#endif
#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
if (request_pac) {
@@ -216,7 +220,7 @@ int ads_kinit_password(ADS_STRUCT *ads)
}
ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
- &ads->auth.expire, NULL, NULL, False, False, ads->auth.renewable);
+ &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable);
if (ret) {
DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
diff --git a/source/libads/ldap_utils.c b/source/libads/ldap_utils.c
index 13782309c72..4edd73c18d7 100644
--- a/source/libads/ldap_utils.c
+++ b/source/libads/ldap_utils.c
@@ -110,10 +110,10 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind
}
SAFE_FREE(bp);
- if (!ADS_ERR_OK(status))
+ if (!ADS_ERR_OK(status)) {
DEBUG(1,("ads reopen failed after error %s\n",
ads_errstr(status)));
-
+ }
return status;
}
diff --git a/source/libads/sasl.c b/source/libads/sasl.c
index 7d1fd0d1a83..61fd54da1da 100644
--- a/source/libads/sasl.c
+++ b/source/libads/sasl.c
@@ -147,7 +147,8 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip
DATA_BLOB session_key = data_blob(NULL, 0);
int rc;
- rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0);
+ rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
+ &ads->auth.tgs_expire);
if (rc) {
return ADS_ERROR_KRB5(rc);
@@ -218,7 +219,7 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
#endif
free(OIDs[i]);
}
- DEBUG(3,("ads_sasl_spnego_bind: got server principal name =%s\n", principal));
+ DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", principal));
#ifdef HAVE_KRB5
if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
@@ -229,6 +230,9 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
return status;
}
+ DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
+ "calling kinit\n", ads_errstr(status)));
+
status = ADS_ERROR_KRB5(ads_kinit_password(ads));
if (ADS_ERR_OK(status)) {
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
index f29449cfb22..2742d70194b 100644
--- a/source/libsmb/cliconnect.c
+++ b/source/libsmb/cliconnect.c
@@ -554,7 +554,7 @@ static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *
DEBUG(2,("Doing kerberos session setup\n"));
/* generate the encapsulated kerberos5 ticket */
- rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0);
+ rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
if (rc) {
DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc)));
diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c
index 305139e1f47..f06a19b345c 100644
--- a/source/libsmb/clikrb5.c
+++ b/source/libsmb/clikrb5.c
@@ -551,7 +551,8 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
const krb5_flags ap_req_options,
const char *principal,
krb5_ccache ccache,
- krb5_data *outbuf)
+ krb5_data *outbuf,
+ time_t *expire_time)
{
krb5_error_code retval;
krb5_principal server;
@@ -584,6 +585,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
}
while (!creds_ready && (i < maxtries)) {
+
if ((retval = krb5_get_credentials(context, 0, ccache,
&creds, &credsp))) {
DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
@@ -599,8 +601,9 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
krb5_set_real_time(context, t + time_offset + 1, 0);
}
- if (!ads_cleanup_expired_creds(context, ccache, credsp))
+ if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
creds_ready = True;
+ }
i++;
}
@@ -610,6 +613,10 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
http_timestring((unsigned)credsp->times.endtime),
(unsigned)credsp->times.endtime));
+ if (expire_time) {
+ *expire_time = (time_t)credsp->times.endtime;
+ }
+
in_data.length = 0;
retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
&in_data, credsp, outbuf);
@@ -634,7 +641,9 @@ cleanup_princ:
*/
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
DATA_BLOB *ticket, DATA_BLOB *session_key_krb5,
- uint32 extra_ap_opts, const char *ccname)
+ uint32 extra_ap_opts, const char *ccname,
+ time_t *tgs_expire)
+
{
krb5_error_code retval;
krb5_data packet;
@@ -678,7 +687,8 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset,
&auth_context,
AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
principal,
- ccdef, &packet))) {
+ ccdef, &packet,
+ tgs_expire))) {
goto failed;
}
@@ -1409,7 +1419,7 @@ done:
/* this saves a few linking headaches */
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
- const char *ccname)
+ const char *ccname, time_t *tgs_expire)
{
DEBUG(0,("NO KERBEROS SUPPORT\n"));
return 1;
diff --git a/source/libsmb/clispnego.c b/source/libsmb/clispnego.c
index a01c009b6e3..6aca217e259 100644
--- a/source/libsmb/clispnego.c
+++ b/source/libsmb/clispnego.c
@@ -343,7 +343,8 @@ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
*/
int spnego_gen_negTokenTarg(const char *principal, int time_offset,
DATA_BLOB *targ,
- DATA_BLOB *session_key_krb5, uint32 extra_ap_opts)
+ DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
+ time_t *expire_time)
{
int retval;
DATA_BLOB tkt, tkt_wrapped;
@@ -351,7 +352,8 @@ int spnego_gen_negTokenTarg(const char *principal, int time_offset,
/* get a kerberos ticket for the service and extract the session key */
retval = cli_krb5_get_ticket(principal, time_offset,
- &tkt, session_key_krb5, extra_ap_opts, NULL);
+ &tkt, session_key_krb5, extra_ap_opts, NULL,
+ expire_time);
if (retval)
return retval;
diff --git a/source/nsswitch/idmap_ad.c b/source/nsswitch/idmap_ad.c
index a0ed0847657..fee53a0539e 100644
--- a/source/nsswitch/idmap_ad.c
+++ b/source/nsswitch/idmap_ad.c
@@ -64,16 +64,23 @@ static ADS_STRUCT *ad_idmap_cached_connection_internal(void)
struct in_addr dc_ip;
if (ad_idmap_ads != NULL) {
+
+ time_t expire;
+ time_t now = time(NULL);
+
ads = ad_idmap_ads;
+ expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
+
/* check for a valid structure */
+ DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
+ (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
- DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
- (uint32) ads->auth.expire, (uint32) time(NULL)));
- if ( ads->config.realm && (ads->auth.expire > time(NULL))) {
+ if ( ads->config.realm && (expire > time(NULL))) {
return ads;
} else {
/* we own this ADS_STRUCT so make sure it goes away */
+ DEBUG(7,("Deleting expired krb5 credential cache\n"));
ads->is_mine = True;
ads_destroy( &ads );
ads_kdestroy(WINBIND_CCACHE_NAME);
diff --git a/source/nsswitch/winbindd_ads.c b/source/nsswitch/winbindd_ads.c
index c582ff730b7..5b0a13afa28 100644
--- a/source/nsswitch/winbindd_ads.c
+++ b/source/nsswitch/winbindd_ads.c
@@ -44,17 +44,23 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
DEBUG(10,("ads_cached_connection\n"));
if (domain->private_data) {
- ads = (ADS_STRUCT *)domain->private_data;
+
+ time_t expire;
+ time_t now = time(NULL);
/* check for a valid structure */
+ ads = (ADS_STRUCT *)domain->private_data;
- DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
- (uint32) ads->auth.expire, (uint32) time(NULL)));
- if ( ads->config.realm && (ads->auth.expire > time(NULL))) {
+ expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
+
+ DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
+ (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
+
+ if ( ads->config.realm && (expire > now)) {
return ads;
- }
- else {
+ } else {
/* we own this ADS_STRUCT so make sure it goes away */
+ DEBUG(7,("Deleting expired krb5 credential cache\n"));
ads->is_mine = True;
ads_destroy( &ads );
ads_kdestroy("MEMORY:winbind_ccache");
@@ -998,11 +1004,15 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
if (!ADS_ERR_OK(rc)) {
- /* its a dead connection ; don't destroy it
- through since ads_USN() has already done
- that indirectly */
-
- domain->private_data = NULL;
+ /* its a dead connection, destroy it */
+
+ if (domain->private_data) {
+ ads = (ADS_STRUCT *)domain->private_data;
+ ads->is_mine = True;
+ ads_destroy(&ads);
+ ads_kdestroy("MEMORY:winbind_ccache");
+ domain->private_data = NULL;
+ }
}
return ads_ntstatus(rc);
}
diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c
index fcaad1fb1f8..2a5ca40125e 100644
--- a/source/nsswitch/winbindd_pam.c
+++ b/source/nsswitch/winbindd_pam.c
@@ -598,7 +598,8 @@ static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
&tkt,
&session_key_krb5,
0,
- cc);
+ cc,
+ NULL);
if (krb5_ret) {
DEBUG(1,("winbindd_raw_kerberos_login: failed to get ticket for %s: %s\n",
local_service, error_message(krb5_ret)));
diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c
index 467e652ca99..547f300f3ae 100644
--- a/source/rpc_client/cli_pipe.c
+++ b/source/rpc_client/cli_pipe.c
@@ -927,7 +927,7 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
/* Create the ticket for the service principal and return it in a gss-api wrapped blob. */
ret = cli_krb5_get_ticket(a->service_principal, 0, &tkt,
- &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED, NULL);
+ &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED, NULL, NULL);
if (ret) {
DEBUG(1,("create_krb5_auth_bind_req: cli_krb5_get_ticket for principal %s "
diff --git a/source/utils/ntlm_auth.c b/source/utils/ntlm_auth.c
index 28de39c4f45..1e7b361e860 100644
--- a/source/utils/ntlm_auth.c
+++ b/source/utils/ntlm_auth.c
@@ -1424,7 +1424,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
spnego.negTokenInit.mechListMIC.length);
principal[spnego.negTokenInit.mechListMIC.length] = '\0';
- retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL);
+ retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
if (retval) {
@@ -1446,7 +1446,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
return False;
}
- retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL);
+ retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
if (retval) {
DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));