lib/util: add debug_set_forced_log_priority()
[Samba.git] / source3 / libads / sasl.c
blob1bcfe0490a82f00fb470987844783e625b51f950
1 /*
2 Unix SMB/CIFS implementation.
3 ads sasl code
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "auth/credentials/credentials.h"
23 #include "auth/gensec/gensec.h"
24 #include "auth_generic.h"
25 #include "ads.h"
26 #include "smb_krb5.h"
27 #include "system/gssapi.h"
28 #include "lib/param/loadparm.h"
29 #include "krb5_env.h"
31 #ifdef HAVE_LDAP
33 static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
34 uint8_t *buf, uint32_t len)
36 struct gensec_security *gensec_security =
37 talloc_get_type_abort(wrap->wrap_private_data,
38 struct gensec_security);
39 NTSTATUS nt_status;
40 DATA_BLOB unwrapped, wrapped;
41 TALLOC_CTX *frame = talloc_stackframe();
43 unwrapped = data_blob_const(buf, len);
45 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
46 if (!NT_STATUS_IS_OK(nt_status)) {
47 TALLOC_FREE(frame);
48 return ADS_ERROR_NT(nt_status);
51 if ((wrap->out.size - 4) < wrapped.length) {
52 TALLOC_FREE(frame);
53 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
56 /* copy the wrapped blob to the right location */
57 memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
59 /* set how many bytes must be written to the underlying socket */
60 wrap->out.left = 4 + wrapped.length;
62 TALLOC_FREE(frame);
64 return ADS_SUCCESS;
67 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
69 struct gensec_security *gensec_security =
70 talloc_get_type_abort(wrap->wrap_private_data,
71 struct gensec_security);
72 NTSTATUS nt_status;
73 DATA_BLOB unwrapped, wrapped;
74 TALLOC_CTX *frame = talloc_stackframe();
76 wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
78 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
79 if (!NT_STATUS_IS_OK(nt_status)) {
80 TALLOC_FREE(frame);
81 return ADS_ERROR_NT(nt_status);
84 if (wrapped.length < unwrapped.length) {
85 TALLOC_FREE(frame);
86 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
89 /* copy the wrapped blob to the right location */
90 memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
92 /* set how many bytes must be written to the underlying socket */
93 wrap->in.left = unwrapped.length;
94 wrap->in.ofs = 4;
96 TALLOC_FREE(frame);
98 return ADS_SUCCESS;
101 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
103 struct gensec_security *gensec_security =
104 talloc_get_type_abort(wrap->wrap_private_data,
105 struct gensec_security);
107 TALLOC_FREE(gensec_security);
109 wrap->wrap_ops = NULL;
110 wrap->wrap_private_data = NULL;
113 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
114 .name = "gensec",
115 .wrap = ads_sasl_gensec_wrap,
116 .unwrap = ads_sasl_gensec_unwrap,
117 .disconnect = ads_sasl_gensec_disconnect
121 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
122 we fit on one socket??)
124 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
125 const char *sasl,
126 enum credentials_use_kerberos krb5_state,
127 const char *target_service,
128 const char *target_hostname,
129 const DATA_BLOB server_blob)
131 DATA_BLOB blob_in = data_blob_null;
132 DATA_BLOB blob_out = data_blob_null;
133 int rc;
134 NTSTATUS nt_status;
135 ADS_STATUS status;
136 struct auth_generic_state *auth_generic_state;
137 bool use_spnego_principal = lp_client_use_spnego_principal();
138 const char *sasl_list[] = { sasl, NULL };
139 NTTIME end_nt_time;
140 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
142 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
143 if (!NT_STATUS_IS_OK(nt_status)) {
144 return ADS_ERROR_NT(nt_status);
147 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
148 return ADS_ERROR_NT(nt_status);
150 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
151 return ADS_ERROR_NT(nt_status);
153 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
154 return ADS_ERROR_NT(nt_status);
157 if (server_blob.length == 0) {
158 use_spnego_principal = false;
161 if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
162 use_spnego_principal = false;
165 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
166 krb5_state,
167 CRED_SPECIFIED);
169 if (target_service != NULL) {
170 nt_status = gensec_set_target_service(
171 auth_generic_state->gensec_security,
172 target_service);
173 if (!NT_STATUS_IS_OK(nt_status)) {
174 return ADS_ERROR_NT(nt_status);
178 if (target_hostname != NULL) {
179 nt_status = gensec_set_target_hostname(
180 auth_generic_state->gensec_security,
181 target_hostname);
182 if (!NT_STATUS_IS_OK(nt_status)) {
183 return ADS_ERROR_NT(nt_status);
187 if (target_service != NULL && target_hostname != NULL) {
188 use_spnego_principal = false;
191 switch (wrap->wrap_type) {
192 case ADS_SASLWRAP_TYPE_SEAL:
193 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
194 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
195 break;
196 case ADS_SASLWRAP_TYPE_SIGN:
197 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
198 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
199 } else {
201 * windows servers are broken with sign only,
202 * so we let the NTLMSSP backend to seal here,
203 * via GENSEC_FEATURE_LDAP_STYLE.
205 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
206 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
208 break;
209 case ADS_SASLWRAP_TYPE_PLAIN:
210 break;
213 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
214 sasl_list);
215 if (!NT_STATUS_IS_OK(nt_status)) {
216 return ADS_ERROR_NT(nt_status);
219 rc = LDAP_SASL_BIND_IN_PROGRESS;
220 if (use_spnego_principal) {
221 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
222 if (blob_in.length == 0) {
223 TALLOC_FREE(auth_generic_state);
224 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
226 } else {
227 blob_in = data_blob_null;
229 blob_out = data_blob_null;
231 while (true) {
232 struct berval cred, *scred = NULL;
234 nt_status = gensec_update(auth_generic_state->gensec_security,
235 talloc_tos(), blob_in, &blob_out);
236 data_blob_free(&blob_in);
237 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
238 && !NT_STATUS_IS_OK(nt_status))
240 TALLOC_FREE(auth_generic_state);
241 data_blob_free(&blob_out);
242 return ADS_ERROR_NT(nt_status);
245 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
246 break;
249 cred.bv_val = (char *)blob_out.data;
250 cred.bv_len = blob_out.length;
251 scred = NULL;
252 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
253 data_blob_free(&blob_out);
254 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
255 if (scred) {
256 ber_bvfree(scred);
259 TALLOC_FREE(auth_generic_state);
260 return ADS_ERROR(rc);
262 if (scred) {
263 blob_in = data_blob_talloc(talloc_tos(),
264 scred->bv_val,
265 scred->bv_len);
266 if (blob_in.length != scred->bv_len) {
267 ber_bvfree(scred);
268 TALLOC_FREE(auth_generic_state);
269 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
271 ber_bvfree(scred);
272 } else {
273 blob_in = data_blob_null;
275 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
276 break;
280 data_blob_free(&blob_in);
281 data_blob_free(&blob_out);
283 if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
284 bool ok;
286 ok = gensec_have_feature(auth_generic_state->gensec_security,
287 GENSEC_FEATURE_SEAL);
288 if (!ok) {
289 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
290 TALLOC_FREE(auth_generic_state);
291 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
294 ok = gensec_have_feature(auth_generic_state->gensec_security,
295 GENSEC_FEATURE_SIGN);
296 if (!ok) {
297 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
298 TALLOC_FREE(auth_generic_state);
299 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
302 } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
303 bool ok;
305 ok = gensec_have_feature(auth_generic_state->gensec_security,
306 GENSEC_FEATURE_SIGN);
307 if (!ok) {
308 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
309 TALLOC_FREE(auth_generic_state);
310 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
314 ads->auth.tgs_expire = LONG_MAX;
315 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
316 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
317 struct timeval tv;
318 nttime_to_timeval(&tv, end_nt_time);
319 ads->auth.tgs_expire = tv.tv_sec;
322 if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
323 size_t max_wrapped =
324 gensec_max_wrapped_size(auth_generic_state->gensec_security);
325 wrap->out.max_unwrapped =
326 gensec_max_input_size(auth_generic_state->gensec_security);
328 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
330 * Note that we have to truncate this to 0x2C
331 * (taken from a capture with LDAP unbind), as the
332 * signature size is not constant for Kerberos with
333 * arcfour-hmac-md5.
335 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
336 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
337 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
338 &ads_sasl_gensec_ops,
339 auth_generic_state->gensec_security);
340 if (!ADS_ERR_OK(status)) {
341 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
342 ads_errstr(status)));
343 TALLOC_FREE(auth_generic_state);
344 return status;
346 /* Only keep the gensec_security element around long-term */
347 talloc_steal(NULL, auth_generic_state->gensec_security);
349 TALLOC_FREE(auth_generic_state);
351 return ADS_ERROR(rc);
354 #ifdef HAVE_KRB5
355 struct ads_service_principal {
356 char *service;
357 char *hostname;
358 char *string;
361 static void ads_free_service_principal(struct ads_service_principal *p)
363 SAFE_FREE(p->service);
364 SAFE_FREE(p->hostname);
365 SAFE_FREE(p->string);
366 ZERO_STRUCTP(p);
369 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
370 char **service,
371 char **hostname,
372 char **principal)
374 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
375 char *princ = NULL;
376 TALLOC_CTX *frame;
377 char *server = NULL;
378 char *realm = NULL;
379 int rc;
381 frame = talloc_stackframe();
382 if (frame == NULL) {
383 return ADS_ERROR(LDAP_NO_MEMORY);
386 if (ads->server.realm && ads->server.ldap_server) {
387 server = strlower_talloc(frame, ads->server.ldap_server);
388 if (server == NULL) {
389 goto out;
392 realm = strupper_talloc(frame, ads->server.realm);
393 if (realm == NULL) {
394 goto out;
398 * If we got a name which is bigger than a NetBIOS name,
399 * but isn't a FQDN, create one.
401 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
402 char *dnsdomain;
404 dnsdomain = strlower_talloc(frame, ads->server.realm);
405 if (dnsdomain == NULL) {
406 goto out;
409 server = talloc_asprintf(frame,
410 "%s.%s",
411 server, dnsdomain);
412 if (server == NULL) {
413 goto out;
416 } else if (ads->config.realm && ads->config.ldap_server_name) {
417 server = strlower_talloc(frame, ads->config.ldap_server_name);
418 if (server == NULL) {
419 goto out;
422 realm = strupper_talloc(frame, ads->config.realm);
423 if (realm == NULL) {
424 goto out;
428 * If we got a name which is bigger than a NetBIOS name,
429 * but isn't a FQDN, create one.
431 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
432 char *dnsdomain;
434 dnsdomain = strlower_talloc(frame, ads->server.realm);
435 if (dnsdomain == NULL) {
436 goto out;
439 server = talloc_asprintf(frame,
440 "%s.%s",
441 server, dnsdomain);
442 if (server == NULL) {
443 goto out;
448 if (server == NULL || realm == NULL) {
449 goto out;
452 *service = SMB_STRDUP("ldap");
453 if (*service == NULL) {
454 status = ADS_ERROR(LDAP_PARAM_ERROR);
455 goto out;
457 *hostname = SMB_STRDUP(server);
458 if (*hostname == NULL) {
459 SAFE_FREE(*service);
460 status = ADS_ERROR(LDAP_PARAM_ERROR);
461 goto out;
463 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
464 if (rc == -1 || princ == NULL) {
465 SAFE_FREE(*service);
466 SAFE_FREE(*hostname);
467 status = ADS_ERROR(LDAP_PARAM_ERROR);
468 goto out;
471 *principal = princ;
473 status = ADS_SUCCESS;
474 out:
475 TALLOC_FREE(frame);
476 return status;
479 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
480 struct ads_service_principal *p)
482 ADS_STATUS status;
484 ZERO_STRUCTP(p);
486 status = ads_guess_target(ads,
487 &p->service,
488 &p->hostname,
489 &p->string);
490 if (!ADS_ERR_OK(status)) {
491 return status;
494 return ADS_SUCCESS;
497 #endif /* HAVE_KRB5 */
500 this performs a SASL/SPNEGO bind
502 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
504 TALLOC_CTX *frame = talloc_stackframe();
505 struct ads_service_principal p = {0};
506 struct berval *scred=NULL;
507 int rc, i;
508 ADS_STATUS status;
509 DATA_BLOB blob = data_blob_null;
510 char *given_principal = NULL;
511 char *OIDs[ASN1_MAX_OIDS];
512 #ifdef HAVE_KRB5
513 bool got_kerberos_mechanism = False;
514 #endif
515 const char *mech = NULL;
517 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
519 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
520 status = ADS_ERROR(rc);
521 goto done;
524 blob = data_blob(scred->bv_val, scred->bv_len);
526 ber_bvfree(scred);
528 #if 0
529 file_save("sasl_spnego.dat", blob.data, blob.length);
530 #endif
532 /* the server sent us the first part of the SPNEGO exchange in the negprot
533 reply */
534 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
535 OIDs[0] == NULL) {
536 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
537 goto done;
539 TALLOC_FREE(given_principal);
541 /* make sure the server understands kerberos */
542 for (i=0;OIDs[i];i++) {
543 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
544 #ifdef HAVE_KRB5
545 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
546 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
547 got_kerberos_mechanism = True;
549 #endif
550 talloc_free(OIDs[i]);
553 status = ads_generate_service_principal(ads, &p);
554 if (!ADS_ERR_OK(status)) {
555 goto done;
558 #ifdef HAVE_KRB5
559 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
560 got_kerberos_mechanism)
562 mech = "KRB5";
564 if (ads->auth.password == NULL ||
565 ads->auth.password[0] == '\0')
568 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
569 CRED_USE_KERBEROS_REQUIRED,
570 p.service, p.hostname,
571 blob);
572 if (ADS_ERR_OK(status)) {
573 ads_free_service_principal(&p);
574 goto done;
577 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
578 "calling kinit\n", ads_errstr(status)));
581 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
583 if (ADS_ERR_OK(status)) {
584 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
585 CRED_USE_KERBEROS_REQUIRED,
586 p.service, p.hostname,
587 blob);
588 if (!ADS_ERR_OK(status)) {
589 DBG_ERR("kinit succeeded but "
590 "SPNEGO bind with Kerberos failed "
591 "for %s/%s - user[%s], realm[%s]: %s\n",
592 p.service, p.hostname,
593 ads->auth.user_name,
594 ads->auth.realm,
595 ads_errstr(status));
599 /* only fallback to NTLMSSP if allowed */
600 if (ADS_ERR_OK(status) ||
601 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
602 goto done;
605 DBG_WARNING("SASL bind with Kerberos failed "
606 "for %s/%s - user[%s], realm[%s]: %s, "
607 "try to fallback to NTLMSSP\n",
608 p.service, p.hostname,
609 ads->auth.user_name,
610 ads->auth.realm,
611 ads_errstr(status));
613 #endif
615 /* lets do NTLMSSP ... this has the big advantage that we don't need
616 to sync clocks, and we don't rely on special versions of the krb5
617 library for HMAC_MD4 encryption */
618 mech = "NTLMSSP";
620 if (!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
621 DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
622 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
623 goto done;
626 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
627 DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
628 " disallowed.\n");
629 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
630 goto done;
633 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
634 CRED_USE_KERBEROS_DISABLED,
635 p.service, p.hostname,
636 data_blob_null);
637 done:
638 if (!ADS_ERR_OK(status)) {
639 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
640 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
641 p.service, p.hostname,
642 ads->auth.user_name,
643 ads->auth.realm,
644 ads_errstr(status)));
646 ads_free_service_principal(&p);
647 TALLOC_FREE(frame);
648 if (blob.data != NULL) {
649 data_blob_free(&blob);
651 return status;
654 /* mapping between SASL mechanisms and functions */
655 static struct {
656 const char *name;
657 ADS_STATUS (*fn)(ADS_STRUCT *);
658 } sasl_mechanisms[] = {
659 {"GSS-SPNEGO", ads_sasl_spnego_bind},
660 {NULL, NULL}
663 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
665 const char *attrs[] = {"supportedSASLMechanisms", NULL};
666 char **values;
667 ADS_STATUS status;
668 int i, j;
669 LDAPMessage *res;
670 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
672 /* get a list of supported SASL mechanisms */
673 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
674 if (!ADS_ERR_OK(status)) return status;
676 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
678 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
679 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
680 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
681 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
682 } else {
683 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
686 /* try our supported mechanisms in order */
687 for (i=0;sasl_mechanisms[i].name;i++) {
688 /* see if the server supports it */
689 for (j=0;values && values[j];j++) {
690 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
691 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
692 retry:
693 status = sasl_mechanisms[i].fn(ads);
694 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
695 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
696 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
698 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
699 "retrying with signing enabled\n"));
700 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
701 goto retry;
703 ldap_value_free(values);
704 ldap_msgfree(res);
705 return status;
710 ldap_value_free(values);
711 ldap_msgfree(res);
712 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
715 #endif /* HAVE_LDAP */