View | Details | Raw Unified | Return to bug 29083
Collapse All | Expand All

(-)a/auth/credentials/credentials.h (+3 lines)
 Lines 182-187   int cli_credentials_get_named_ccache(struct cli_credentials *cred, Link Here 
182
				     struct loadparm_context *lp_ctx,
182
				     struct loadparm_context *lp_ctx,
183
				     char *ccache_name,
183
				     char *ccache_name,
184
				     struct ccache_container **ccc, const char **error_string);
184
				     struct ccache_container **ccc, const char **error_string);
185
bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred,
186
					   const char *principal,
187
					   unsigned int *count);
185
int cli_credentials_get_keytab(struct cli_credentials *cred, 
188
int cli_credentials_get_keytab(struct cli_credentials *cred, 
186
			       struct loadparm_context *lp_ctx,
189
			       struct loadparm_context *lp_ctx,
187
			       struct keytab_container **_ktc);
190
			       struct keytab_container **_ktc);
(-)a/auth/credentials/credentials_krb5.c (-2 / +61 lines)
 Lines 212-217   _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred, Link Here 
212
	return 0;
212
	return 0;
213
}
213
}
214
214
215
/*
216
 * Indicate the we failed to log in to this service/host with these
217
 * credentials.  The caller passes an unsigned int which they
218
 * initialise to the number of times they would like to retry.
219
 *
220
 * This method is used to support re-trying with freshly fetched
221
 * credentials in case a server is rebuilt while clients have
222
 * non-expired tickets. When the client code gets a logon failure they
223
 * throw away the existing credentials for the server and retry.
224
 */
225
_PUBLIC_ bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred,
226
						    const char *principal,
227
						    unsigned int *count)
228
{
229
	struct ccache_container *ccc;
230
	krb5_creds creds, creds2;
231
	int ret;
232
233
	if (principal == NULL) {
234
		/* no way to delete if we don't know the principal */
235
		return false;
236
	}
237
238
	ccc = cred->ccache;
239
	if (ccc == NULL) {
240
		/* not a kerberos connection */
241
		return false;
242
	}
243
244
	if (*count > 0) {
245
		/* We have already tried discarding the credentials */
246
		return false;
247
	}
248
	(*count)++;
249
250
	ZERO_STRUCT(creds);
251
	ret = krb5_parse_name(ccc->smb_krb5_context->krb5_context, principal, &creds.server);
252
	if (ret != 0) {
253
		return false;
254
	}
255
256
	ret = krb5_cc_retrieve_cred(ccc->smb_krb5_context->krb5_context, ccc->ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &creds, &creds2);
257
	if (ret != 0) {
258
		/* don't retry - we didn't find these credentials to remove */
259
		return false;
260
	}
261
262
	ret = krb5_cc_remove_cred(ccc->smb_krb5_context->krb5_context, ccc->ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &creds);
263
	krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context, &creds2);
264
	if (ret != 0) {
265
		/* don't retry - we didn't find these credentials to
266
		 * remove. Note that with the current backend this
267
		 * never happens, as it always returns 0 even if the
268
		 * creds don't exist, which is why we do a separate
269
		 * krb5_cc_retrieve_cred() above.
270
		 */
271
		return false;
272
	}
273
	return true;
274
}
275
215
276
216
static int cli_credentials_new_ccache(struct cli_credentials *cred, 
277
static int cli_credentials_new_ccache(struct cli_credentials *cred, 
217
				      struct loadparm_context *lp_ctx,
278
				      struct loadparm_context *lp_ctx,
218
- 
219
cope with server changes
279
cope with server changes
220
--
221
source4/libcli/smb_composite/sesssetup.c | 17 +++++++++++++++--
280
source4/libcli/smb_composite/sesssetup.c | 17 +++++++++++++++--
222
1 file changed, 15 insertions(+), 2 deletions(-)
281
1 file changed, 15 insertions(+), 2 deletions(-)
(-)a/source4/libcli/smb_composite/sesssetup.c (-4 / +15 lines)
 Lines 39-44   struct sesssetup_state { Link Here 
39
	NTSTATUS gensec_status;
39
	NTSTATUS gensec_status;
40
	struct smb_composite_sesssetup *io;
40
	struct smb_composite_sesssetup *io;
41
	struct smbcli_request *req;
41
	struct smbcli_request *req;
42
	unsigned int logon_retries;
42
};
43
};
43
44
44
static int sesssetup_state_destructor(struct sesssetup_state *state)
45
static int sesssetup_state_destructor(struct sesssetup_state *state)
 Lines 123-129   static void request_handler(struct smbcli_request *req) Link Here 
123
	case RAW_SESSSETUP_NT1:
124
	case RAW_SESSSETUP_NT1:
124
		state->io->out.vuid = state->setup.nt1.out.vuid;
125
		state->io->out.vuid = state->setup.nt1.out.vuid;
125
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
126
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
126
			/* we neet to reset the vuid for a new try */
127
			/* we need to reset the vuid for a new try */
127
			session->vuid = 0;
128
			session->vuid = 0;
128
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
129
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
129
				nt_status = session_setup_nt1(c, session, 
130
				nt_status = session_setup_nt1(c, session, 
 Lines 144-152   static void request_handler(struct smbcli_request *req) Link Here 
144
	case RAW_SESSSETUP_SPNEGO:
145
	case RAW_SESSSETUP_SPNEGO:
145
		state->io->out.vuid = state->setup.spnego.out.vuid;
146
		state->io->out.vuid = state->setup.spnego.out.vuid;
146
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
147
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
148
			const char *principal;
149
147
			/* we need to reset the vuid for a new try */
150
			/* we need to reset the vuid for a new try */
148
			session->vuid = 0;
151
			session->vuid = 0;
149
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
152
153
			principal = gensec_get_target_principal(session->gensec);
154
			if (principal == NULL) {
155
				const char *hostname = gensec_get_target_hostname(session->gensec);
156
				const char *service  = gensec_get_target_service(session->gensec);
157
				if (hostname != NULL && service != NULL) {
158
					principal = talloc_asprintf(state, "%s/%s", service, hostname);
159
				}
160
			}
161
			if (cli_credentials_failed_kerberos_login(state->io->in.credentials, principal, &state->logon_retries) ||
162
			    cli_credentials_wrong_password(state->io->in.credentials)) {
150
				nt_status = session_setup_spnego(c, session, 
163
				nt_status = session_setup_spnego(c, session, 
151
								      state->io, 
164
								      state->io, 
152
								      &state->req);
165
								      &state->req);
153
- 
154
--
155
testprogs/blackbox/test_chgdcpass.sh | 5 +++++
166
testprogs/blackbox/test_chgdcpass.sh | 5 +++++
156
1 file changed, 5 insertions(+)
167
1 file changed, 5 insertions(+)
(-)a/testprogs/blackbox/test_chgdcpass.sh (-2 / +5 lines)
 Lines 59-64   testit "change dc password" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR Link Here 
59
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC password is changed
59
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC password is changed
60
test_smbclient "Test login with kerberos ccache after password change" 'ls' -k yes || failed=`expr $failed + 1`
60
test_smbclient "Test login with kerberos ccache after password change" 'ls' -k yes || failed=`expr $failed + 1`
61
61
62
testit "change dc password (2nd time)" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
63
64
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC pass
65
test_smbclient "Test login with kerberos ccache after 2nd password change" 'ls' -k yes || failed=`expr $failed + 1`
66
62
#This confirms that the DC password is valid for a kinit too
67
#This confirms that the DC password is valid for a kinit too
63
testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
68
testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
64
test_smbclient "Test login with kerberos ccache with fresh kinit" 'ls' -k yes || failed=`expr $failed + 1`
69
test_smbclient "Test login with kerberos ccache with fresh kinit" 'ls' -k yes || failed=`expr $failed + 1`
65
- 
66
to cope with stale tickets
70
to cope with stale tickets
67
--
68
source4/librpc/rpc/dcerpc_util.c | 16 +++++++++++++++-
71
source4/librpc/rpc/dcerpc_util.c | 16 +++++++++++++++-
69
1 file changed, 15 insertions(+), 1 deletion(-)
72
1 file changed, 15 insertions(+), 1 deletion(-)
(-)a/source4/librpc/rpc/dcerpc_util.c (-3 / +15 lines)
 Lines 30-35    Link Here 
30
#include "librpc/gen_ndr/ndr_misc.h"
30
#include "librpc/gen_ndr/ndr_misc.h"
31
#include "librpc/rpc/dcerpc_proto.h"
31
#include "librpc/rpc/dcerpc_proto.h"
32
#include "auth/credentials/credentials.h"
32
#include "auth/credentials/credentials.h"
33
#include "auth/gensec/gensec.h"
33
#include "param/param.h"
34
#include "param/param.h"
34
#include "librpc/rpc/rpc_common.h"
35
#include "librpc/rpc/rpc_common.h"
35
36
 Lines 335-340   struct pipe_auth_state { Link Here 
335
	const struct ndr_interface_table *table;
336
	const struct ndr_interface_table *table;
336
	struct loadparm_context *lp_ctx;
337
	struct loadparm_context *lp_ctx;
337
	struct cli_credentials *credentials;
338
	struct cli_credentials *credentials;
339
	unsigned int logon_retries;
338
};
340
};
339
341
340
342
 Lines 395-401   static void continue_auth_auto(struct composite_context *ctx) Link Here 
395
		composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
397
		composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
396
		return;
398
		return;
397
	} else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
399
	} else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
398
		if (cli_credentials_wrong_password(s->credentials)) {
400
		const char *principal;
401
402
		principal = gensec_get_target_principal(s->pipe->conn->security_state.generic_state);
403
		if (principal == NULL) {
404
			const char *hostname = gensec_get_target_hostname(s->pipe->conn->security_state.generic_state);
405
			const char *service  = gensec_get_target_service(s->pipe->conn->security_state.generic_state);
406
			if (hostname != NULL && service != NULL) {
407
				principal = talloc_asprintf(c, "%s/%s", service, hostname);
408
			}
409
		}
410
411
		if (cli_credentials_failed_kerberos_login(s->credentials, principal, &s->logon_retries) ||
412
		    cli_credentials_wrong_password(s->credentials)) {
399
			/*
413
			/*
400
			 * Retry SPNEGO with a better password
414
			 * Retry SPNEGO with a better password
401
			 * send a request for secondary rpc connection
415
			 * send a request for secondary rpc connection
402
- 
403
RPC
416
RPC
404
--
405
testprogs/blackbox/test_chgdcpass.sh | 25 +++++++++++++++++++++++++
417
testprogs/blackbox/test_chgdcpass.sh | 25 +++++++++++++++++++++++++
406
1 file changed, 25 insertions(+)
418
1 file changed, 25 insertions(+)
(-)a/testprogs/blackbox/test_chgdcpass.sh (-2 / +25 lines)
 Lines 45-50   test_smbclient() { Link Here 
45
	return $status
45
	return $status
46
}
46
}
47
47
48
test_drsbind() {
49
	name="$1"
50
	shift
51
	echo "test: $name"
52
	echo $VALGRIND $samba4bindir/samba-tool drs bind $SERVER -k yes $@
53
	$VALGRIND $samba4bindir/samba-tool drs bind $SERVER -k yes $@
54
	status=$?
55
	if [ x$status = x0 ]; then
56
		echo "success: $name"
57
	else
58
		echo "failure: $name"
59
	fi
60
	return $status
61
}
62
48
enctype="-e $ENCTYPE"
63
enctype="-e $ENCTYPE"
49
64
50
KRB5CCNAME="$PREFIX/tmpccache"
65
KRB5CCNAME="$PREFIX/tmpccache"
 Lines 54-69   testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.key Link Here 
54
69
55
#This is important because it puts the ticket for the old KVNO and password into a local ccache
70
#This is important because it puts the ticket for the old KVNO and password into a local ccache
56
test_smbclient "Test login with kerberos ccache before password change" 'ls' -k yes || failed=`expr $failed + 1`
71
test_smbclient "Test login with kerberos ccache before password change" 'ls' -k yes || failed=`expr $failed + 1`
72
73
#check that drs options works before we change the password (prime the ccache)
74
test_drsbind "Test drs options with with kerberos ccache" || failed=`expr $failed + 1`
75
57
testit "change dc password" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
76
testit "change dc password" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
58
77
59
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC password is changed
78
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC password is changed
60
test_smbclient "Test login with kerberos ccache after password change" 'ls' -k yes || failed=`expr $failed + 1`
79
test_smbclient "Test login with kerberos ccache after password change" 'ls' -k yes || failed=`expr $failed + 1`
61
80
81
#check that drs options works after we change the password
82
test_drsbind "Test drs options with new password" || failed=`expr $failed + 1`
83
62
testit "change dc password (2nd time)" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
84
testit "change dc password (2nd time)" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
63
85
64
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC pass
86
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC pass
65
test_smbclient "Test login with kerberos ccache after 2nd password change" 'ls' -k yes || failed=`expr $failed + 1`
87
test_smbclient "Test login with kerberos ccache after 2nd password change" 'ls' -k yes || failed=`expr $failed + 1`
66
88
89
#check that drs options works after we change the password a 2nd time
90
test_drsbind "Test drs options after 2nd password change" || failed=`expr $failed + 1`
91
67
#This confirms that the DC password is valid for a kinit too
92
#This confirms that the DC password is valid for a kinit too
68
testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
93
testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
69
test_smbclient "Test login with kerberos ccache with fresh kinit" 'ls' -k yes || failed=`expr $failed + 1`
94
test_smbclient "Test login with kerberos ccache with fresh kinit" 'ls' -k yes || failed=`expr $failed + 1`
70
- 
71
--
72
source4/librpc/rpc/dcerpc_util.c | 13 ++++++++++---
95
source4/librpc/rpc/dcerpc_util.c | 13 ++++++++++---
73
1 file changed, 10 insertions(+), 3 deletions(-)
96
1 file changed, 10 insertions(+), 3 deletions(-)
(-)a/source4/librpc/rpc/dcerpc_util.c (-5 / +10 lines)
 Lines 396-402   static void continue_auth_auto(struct composite_context *ctx) Link Here 
396
								s->binding);
396
								s->binding);
397
		composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
397
		composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
398
		return;
398
		return;
399
	} else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
399
	} else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE) ||
400
		   NT_STATUS_EQUAL(c->status, NT_STATUS_UNSUCCESSFUL)) {
401
		/*
402
		  try a second time on any error. We don't just do it
403
		  on LOGON_FAILURE as some servers will give a
404
		  NT_STATUS_UNSUCCESSFUL on a authentication error on RPC
405
		 */
400
		const char *principal;
406
		const char *principal;
401
407
402
		principal = gensec_get_target_principal(s->pipe->conn->security_state.generic_state);
408
		principal = gensec_get_target_principal(s->pipe->conn->security_state.generic_state);
 Lines 408-415   static void continue_auth_auto(struct composite_context *ctx) Link Here 
408
			}
414
			}
409
		}
415
		}
410
416
411
		if (cli_credentials_failed_kerberos_login(s->credentials, principal, &s->logon_retries) ||
417
		if ((cli_credentials_failed_kerberos_login(s->credentials, principal, &s->logon_retries) ||
412
		    cli_credentials_wrong_password(s->credentials)) {
418
		     cli_credentials_wrong_password(s->credentials)) &&
419
		    s->binding->endpoint != NULL) {
413
			/*
420
			/*
414
			 * Retry SPNEGO with a better password
421
			 * Retry SPNEGO with a better password
415
			 * send a request for secondary rpc connection
422
			 * send a request for secondary rpc connection
416
- 
417
connection
423
connection
418
--
419
source4/scripting/python/samba/netcmd/drs.py | 1 -
424
source4/scripting/python/samba/netcmd/drs.py | 1 -
420
1 file changed, 1 deletion(-)
425
1 file changed, 1 deletion(-)
(-)a/source4/scripting/python/samba/netcmd/drs.py (-3 lines)
 Lines 361-367   class cmd_drs_bind(Command): Link Here 
361
        self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
361
        self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
362
362
363
        drsuapi_connect(self)
363
        drsuapi_connect(self)
364
        samdb_connect(self)
365
364
366
        bind_info = drsuapi.DsBindInfoCtr()
365
        bind_info = drsuapi.DsBindInfoCtr()
367
        bind_info.length = 28
366
        bind_info.length = 28
368
- 
369
fault with access denied
367
fault with access denied
370
--
371
source4/librpc/rpc/dcerpc.c | 9 +++++++--
368
source4/librpc/rpc/dcerpc.c | 9 +++++++--
372
1 file changed, 7 insertions(+), 2 deletions(-)
369
1 file changed, 7 insertions(+), 2 deletions(-)
(-)a/source4/librpc/rpc/dcerpc.c (-4 / +7 lines)
 Lines 2148-2155   static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq, Link Here 
2148
	if (pkt->ptype == DCERPC_PKT_FAULT) {
2148
	if (pkt->ptype == DCERPC_PKT_FAULT) {
2149
		DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2149
		DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2150
			 dcerpc_errstr(state, pkt->u.fault.status)));
2150
			 dcerpc_errstr(state, pkt->u.fault.status)));
2151
		state->p->last_fault_code = pkt->u.fault.status;
2151
		if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2152
		tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2152
			state->p->last_fault_code = pkt->u.fault.status;
2153
			tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2154
		} else {
2155
			state->p->last_fault_code = pkt->u.fault.status;
2156
			tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2157
		}
2153
		return;
2158
		return;
2154
	}
2159
	}
2155
2160
2156
- 
2157
--
2158
source4/libcli/ldap/ldap_bind.c | 116 +++++++++++++++++++++++++++-------------
2161
source4/libcli/ldap/ldap_bind.c | 116 +++++++++++++++++++++++++++-------------
2159
1 file changed, 79 insertions(+), 37 deletions(-)
2162
1 file changed, 79 insertions(+), 37 deletions(-)
(-)a/source4/libcli/ldap/ldap_bind.c (-39 / +79 lines)
 Lines 221-229   _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, Link Here 
221
		"supportedSASLMechanisms", 
221
		"supportedSASLMechanisms", 
222
		NULL 
222
		NULL 
223
	};
223
	};
224
	unsigned int logon_retries = 0;
225
226
	status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
227
			      false, NULL, NULL, &sasl_mechs_msgs);
228
	if (!NT_STATUS_IS_OK(status)) {
229
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n",
230
			  nt_errstr(status)));
231
		goto failed;
232
	}
233
234
	count = ildap_count_entries(conn, sasl_mechs_msgs);
235
	if (count != 1) {
236
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
237
			  count));
238
		goto failed;
239
	}
240
241
	tmp_ctx = talloc_new(conn);
242
	if (tmp_ctx == NULL) goto failed;
243
244
	search = &sasl_mechs_msgs[0]->r.SearchResultEntry;
245
	if (search->num_attributes != 1) {
246
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n",
247
			  search->num_attributes));
248
		goto failed;
249
	}
250
251
	sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1);
252
	if (!sasl_names) {
253
		DEBUG(1, ("talloc_arry(char *, %d) failed\n",
254
			  count));
255
		goto failed;
256
	}
257
258
	for (i=0; i<search->attributes[0].num_values; i++) {
259
		sasl_names[i] = (const char *)search->attributes[0].values[i].data;
260
	}
261
	sasl_names[i] = NULL;
224
262
225
	gensec_init();
263
	gensec_init();
226
264
265
try_logon_again:
266
	/*
267
	  we loop back here on a logon failure, and re-create the
268
	  gensec session. The logon_retries counter ensures we don't
269
	  loop forever.
270
	 */
271
227
	status = gensec_client_start(conn, &conn->gensec,
272
	status = gensec_client_start(conn, &conn->gensec,
228
				     lpcfg_gensec_settings(conn, lp_ctx));
273
				     lpcfg_gensec_settings(conn, lp_ctx));
229
	if (!NT_STATUS_IS_OK(status)) {
274
	if (!NT_STATUS_IS_OK(status)) {
 Lines 266-308   _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, Link Here 
266
		goto failed;
311
		goto failed;
267
	}
312
	}
268
313
269
	status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs, 
270
			      false, NULL, NULL, &sasl_mechs_msgs);
271
	if (!NT_STATUS_IS_OK(status)) {
272
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n", 
273
			  nt_errstr(status)));
274
		goto failed;
275
	}
276
	
277
	count = ildap_count_entries(conn, sasl_mechs_msgs);
278
	if (count != 1) {
279
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
280
			  count));
281
		goto failed;
282
	}
283
284
	tmp_ctx = talloc_new(conn);
285
	if (tmp_ctx == NULL) goto failed;
286
287
	search = &sasl_mechs_msgs[0]->r.SearchResultEntry;
288
	if (search->num_attributes != 1) {
289
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n",
290
			  search->num_attributes));
291
		goto failed;
292
	}
293
294
	sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1);
295
	if (!sasl_names) {
296
		DEBUG(1, ("talloc_arry(char *, %d) failed\n",
297
			  count));
298
		goto failed;
299
	}
300
		
301
	for (i=0; i<search->attributes[0].num_values; i++) {
302
		sasl_names[i] = (const char *)search->attributes[0].values[i].data;
303
	}
304
	sasl_names[i] = NULL;
305
	
306
	status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names);
314
	status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names);
307
	if (!NT_STATUS_IS_OK(status)) {
315
	if (!NT_STATUS_IS_OK(status)) {
308
		DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
316
		DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
 Lines 367-372   _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, Link Here 
367
375
368
		result = response->r.BindResponse.response.resultcode;
376
		result = response->r.BindResponse.response.resultcode;
369
377
378
		if (result == LDAP_INVALID_CREDENTIALS) {
379
			/*
380
			  try a second time on invalid credentials, to
381
			  give the user a chance to re-enter the
382
			  password and to handle the case where our
383
			  kerberos ticket is invalid as the server
384
			  password has changed
385
			*/
386
			const char *principal;
387
388
			principal = gensec_get_target_principal(conn->gensec);
389
			if (principal == NULL) {
390
				const char *hostname = gensec_get_target_hostname(conn->gensec);
391
				const char *service  = gensec_get_target_service(conn->gensec);
392
				if (hostname != NULL && service != NULL) {
393
					principal = talloc_asprintf(tmp_ctx, "%s/%s", service, hostname);
394
				}
395
			}
396
397
			if (cli_credentials_failed_kerberos_login(creds, principal, &logon_retries) ||
398
			    cli_credentials_wrong_password(creds)) {
399
				/*
400
				  destroy our gensec session and loop
401
				  back up to the top to retry,
402
				  offering the user a chance to enter
403
				  new credentials, or get a new ticket
404
				  if using kerberos
405
				 */
406
				talloc_free(conn->gensec);
407
				conn->gensec = NULL;
408
				goto try_logon_again;
409
			}
410
		}
411
370
		if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
412
		if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
371
			status = ldap_check_response(conn, 
413
			status = ldap_check_response(conn, 
372
						     &response->r.BindResponse.response);
414
						     &response->r.BindResponse.response);
373
- 
374
change
415
change
375
--
376
testprogs/blackbox/test_chgdcpass.sh | 25 ++++++++++++++++++-------
416
testprogs/blackbox/test_chgdcpass.sh | 25 ++++++++++++++++++-------
377
1 file changed, 18 insertions(+), 7 deletions(-)
417
1 file changed, 18 insertions(+), 7 deletions(-)
(-)a/testprogs/blackbox/test_chgdcpass.sh (-8 / +18 lines)
 Lines 45-56   test_smbclient() { Link Here 
45
	return $status
45
	return $status
46
}
46
}
47
47
48
test_drsbind() {
48
test_drs() {
49
	name="$1"
49
	function="$1"
50
	name="$2"
51
	shift
50
	shift
52
	shift
51
	echo "test: $name"
53
	echo "test: $name"
52
	echo $VALGRIND $samba4bindir/samba-tool drs bind $SERVER -k yes $@
54
	echo $VALGRIND $samba4bindir/samba-tool drs $function $SERVER -k yes $@
53
	$VALGRIND $samba4bindir/samba-tool drs bind $SERVER -k yes $@
55
	$VALGRIND $samba4bindir/samba-tool drs $function $SERVER -k yes $@
54
	status=$?
56
	status=$?
55
	if [ x$status = x0 ]; then
57
	if [ x$status = x0 ]; then
56
		echo "success: $name"
58
		echo "success: $name"
 Lines 70-93   testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.key Link Here 
70
#This is important because it puts the ticket for the old KVNO and password into a local ccache
72
#This is important because it puts the ticket for the old KVNO and password into a local ccache
71
test_smbclient "Test login with kerberos ccache before password change" 'ls' -k yes || failed=`expr $failed + 1`
73
test_smbclient "Test login with kerberos ccache before password change" 'ls' -k yes || failed=`expr $failed + 1`
72
74
75
#check that drs bind works before we change the password (prime the ccache)
76
test_drs bind "Test drs bind with with kerberos ccache" || failed=`expr $failed + 1`
77
73
#check that drs options works before we change the password (prime the ccache)
78
#check that drs options works before we change the password (prime the ccache)
74
test_drsbind "Test drs options with with kerberos ccache" || failed=`expr $failed + 1`
79
test_drs options "Test drs options with with kerberos ccache" || failed=`expr $failed + 1`
75
80
76
testit "change dc password" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
81
testit "change dc password" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
77
82
78
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC password is changed
83
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC password is changed
79
test_smbclient "Test login with kerberos ccache after password change" 'ls' -k yes || failed=`expr $failed + 1`
84
test_smbclient "Test login with kerberos ccache after password change" 'ls' -k yes || failed=`expr $failed + 1`
80
85
86
#check that drs bind works after we change the password
87
test_drs bind "Test drs bind with new password" || failed=`expr $failed + 1`
88
81
#check that drs options works after we change the password
89
#check that drs options works after we change the password
82
test_drsbind "Test drs options with new password" || failed=`expr $failed + 1`
90
test_drs options "Test drs options with new password" || failed=`expr $failed + 1`
83
91
84
testit "change dc password (2nd time)" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
92
testit "change dc password (2nd time)" $samba4srcdir/scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1`
85
93
86
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC pass
94
#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC pass
87
test_smbclient "Test login with kerberos ccache after 2nd password change" 'ls' -k yes || failed=`expr $failed + 1`
95
test_smbclient "Test login with kerberos ccache after 2nd password change" 'ls' -k yes || failed=`expr $failed + 1`
88
96
97
#check that drs bind works after we change the password a 2nd time
98
test_drs bind "Test drs bind after 2nd password change" || failed=`expr $failed + 1`
99
89
#check that drs options works after we change the password a 2nd time
100
#check that drs options works after we change the password a 2nd time
90
test_drsbind "Test drs options after 2nd password change" || failed=`expr $failed + 1`
101
test_drs options "Test drs options after 2nd password change" || failed=`expr $failed + 1`
91
102
92
#This confirms that the DC password is valid for a kinit too
103
#This confirms that the DC password is valid for a kinit too
93
testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
104
testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
94
- 

Return to bug 29083