s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source3 / libads / sasl.c
1 /*
2    Unix SMB/CIFS implementation.
3    ads sasl code
4    Copyright (C) Andrew Tridgell 2001
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "auth/credentials/credentials.h"
22 #include "auth/gensec/gensec.h"
23 #include "auth_generic.h"
24 #include "ads.h"
25 #include "smb_krb5.h"
26 #include "system/gssapi.h"
27 #include "lib/param/loadparm.h"
28 #include "krb5_env.h"
29 #include "lib/util/asn1.h"
30
31 #ifdef HAVE_LDAP
32
33 static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
34                                        uint8_t *buf, uint32_t len)
35 {
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();
42
43         unwrapped = data_blob_const(buf, len);
44
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);
49         }
50
51         if ((wrap->out.size - 4) < wrapped.length) {
52                 TALLOC_FREE(frame);
53                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
54         }
55
56         /* copy the wrapped blob to the right location */
57         memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
58
59         /* set how many bytes must be written to the underlying socket */
60         wrap->out.left = 4 + wrapped.length;
61
62         TALLOC_FREE(frame);
63
64         return ADS_SUCCESS;
65 }
66
67 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
68 {
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();
75
76         wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
77
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);
82         }
83
84         if (wrapped.length < unwrapped.length) {
85                 TALLOC_FREE(frame);
86                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
87         }
88
89         /* copy the wrapped blob to the right location */
90         memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
91
92         /* set how many bytes must be written to the underlying socket */
93         wrap->in.left   = unwrapped.length;
94         wrap->in.ofs    = 4;
95
96         TALLOC_FREE(frame);
97
98         return ADS_SUCCESS;
99 }
100
101 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
102 {
103         struct gensec_security *gensec_security =
104                 talloc_get_type_abort(wrap->wrap_private_data,
105                 struct gensec_security);
106
107         TALLOC_FREE(gensec_security);
108
109         wrap->wrap_ops = NULL;
110         wrap->wrap_private_data = NULL;
111 }
112
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
118 };
119
120 /*
121    perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
122    we fit on one socket??)
123 */
124 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
125                                 enum credentials_use_kerberos krb5_state,
126                                 const char *target_service,
127                                 const char *target_hostname)
128 {
129         DATA_BLOB blob_in = data_blob_null;
130         DATA_BLOB blob_out = data_blob_null;
131         int rc;
132         NTSTATUS nt_status;
133         ADS_STATUS status;
134         struct auth_generic_state *auth_generic_state;
135         const char *sasl = "GSS-SPNEGO";
136         const char *sasl_list[] = { sasl, NULL };
137         NTTIME end_nt_time;
138         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
139         const DATA_BLOB *tls_cb = NULL;
140
141         nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
142         if (!NT_STATUS_IS_OK(nt_status)) {
143                 return ADS_ERROR_NT(nt_status);
144         }
145
146         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
147                 return ADS_ERROR_NT(nt_status);
148         }
149         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
150                 return ADS_ERROR_NT(nt_status);
151         }
152         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
153                 return ADS_ERROR_NT(nt_status);
154         }
155
156         cli_credentials_set_kerberos_state(auth_generic_state->credentials,
157                                            krb5_state,
158                                            CRED_SPECIFIED);
159
160         if (target_service != NULL) {
161                 nt_status = gensec_set_target_service(
162                                         auth_generic_state->gensec_security,
163                                         target_service);
164                 if (!NT_STATUS_IS_OK(nt_status)) {
165                         return ADS_ERROR_NT(nt_status);
166                 }
167         }
168
169         if (target_hostname != NULL) {
170                 nt_status = gensec_set_target_hostname(
171                                         auth_generic_state->gensec_security,
172                                         target_hostname);
173                 if (!NT_STATUS_IS_OK(nt_status)) {
174                         return ADS_ERROR_NT(nt_status);
175                 }
176         }
177
178         tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
179         if (tls_cb != NULL) {
180                 uint32_t initiator_addrtype = 0;
181                 const DATA_BLOB *initiator_address = NULL;
182                 uint32_t acceptor_addrtype = 0;
183                 const DATA_BLOB *acceptor_address = NULL;
184                 const DATA_BLOB *application_data = tls_cb;
185
186                 nt_status = gensec_set_channel_bindings(auth_generic_state->gensec_security,
187                                                         initiator_addrtype,
188                                                         initiator_address,
189                                                         acceptor_addrtype,
190                                                         acceptor_address,
191                                                         application_data);
192                 if (!NT_STATUS_IS_OK(nt_status)) {
193                         DBG_WARNING("Failed to set GENSEC channel bindings: %s\n",
194                                     nt_errstr(nt_status));
195                         return ADS_ERROR_NT(nt_status);
196                 }
197         }
198
199         switch (wrap->wrap_type) {
200         case ADS_SASLWRAP_TYPE_SEAL:
201                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
202                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
203                 break;
204         case ADS_SASLWRAP_TYPE_SIGN:
205                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
206                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
207                 } else {
208                         /*
209                          * windows servers are broken with sign only,
210                          * so we let the NTLMSSP backend to seal here,
211                          * via GENSEC_FEATURE_LDAP_STYLE.
212                          */
213                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
214                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
215                 }
216                 break;
217         case ADS_SASLWRAP_TYPE_PLAIN:
218                 break;
219         }
220
221         nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
222                                                       sasl_list);
223         if (!NT_STATUS_IS_OK(nt_status)) {
224                 return ADS_ERROR_NT(nt_status);
225         }
226
227         rc = LDAP_SASL_BIND_IN_PROGRESS;
228         blob_in = data_blob_null;
229         blob_out = data_blob_null;
230
231         while (true) {
232                 struct berval cred, *scred = NULL;
233
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))
239                 {
240                         TALLOC_FREE(auth_generic_state);
241                         data_blob_free(&blob_out);
242                         return ADS_ERROR_NT(nt_status);
243                 }
244
245                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
246                         break;
247                 }
248
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);
257                         }
258
259                         TALLOC_FREE(auth_generic_state);
260                         return ADS_ERROR(rc);
261                 }
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);
270                         }
271                         ber_bvfree(scred);
272                 } else {
273                         blob_in = data_blob_null;
274                 }
275                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
276                         break;
277                 }
278         }
279
280         data_blob_free(&blob_in);
281         data_blob_free(&blob_out);
282
283         if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
284                 bool ok;
285
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);
292                 }
293
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);
300                 }
301
302         } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
303                 bool ok;
304
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);
311                 }
312         }
313
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;
320         }
321
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);
327
328                 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
329                 /*
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.
334                  */
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;
345                 }
346                 /* Only keep the gensec_security element around long-term */
347                 talloc_steal(NULL, auth_generic_state->gensec_security);
348         }
349         TALLOC_FREE(auth_generic_state);
350
351         return ADS_ERROR(rc);
352 }
353
354 #ifdef HAVE_KRB5
355 struct ads_service_principal {
356         char *service;
357         char *hostname;
358         char *string;
359 };
360
361 static void ads_free_service_principal(struct ads_service_principal *p)
362 {
363         SAFE_FREE(p->service);
364         SAFE_FREE(p->hostname);
365         SAFE_FREE(p->string);
366         ZERO_STRUCTP(p);
367 }
368
369 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
370                                    char **service,
371                                    char **hostname,
372                                    char **principal)
373 {
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;
380
381         frame = talloc_stackframe();
382         if (frame == NULL) {
383                 return ADS_ERROR(LDAP_NO_MEMORY);
384         }
385
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;
390                 }
391
392                 realm = strupper_talloc(frame, ads->server.realm);
393                 if (realm == NULL) {
394                         goto out;
395                 }
396
397                 /*
398                  * If we got a name which is bigger than a NetBIOS name,
399                  * but isn't a FQDN, create one.
400                  */
401                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
402                         char *dnsdomain;
403
404                         dnsdomain = strlower_talloc(frame, ads->server.realm);
405                         if (dnsdomain == NULL) {
406                                 goto out;
407                         }
408
409                         server = talloc_asprintf(frame,
410                                                  "%s.%s",
411                                                  server, dnsdomain);
412                         if (server == NULL) {
413                                 goto out;
414                         }
415                 }
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;
420                 }
421
422                 realm = strupper_talloc(frame, ads->config.realm);
423                 if (realm == NULL) {
424                         goto out;
425                 }
426
427                 /*
428                  * If we got a name which is bigger than a NetBIOS name,
429                  * but isn't a FQDN, create one.
430                  */
431                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
432                         char *dnsdomain;
433
434                         dnsdomain = strlower_talloc(frame, ads->server.realm);
435                         if (dnsdomain == NULL) {
436                                 goto out;
437                         }
438
439                         server = talloc_asprintf(frame,
440                                                  "%s.%s",
441                                                  server, dnsdomain);
442                         if (server == NULL) {
443                                 goto out;
444                         }
445                 }
446         }
447
448         if (server == NULL || realm == NULL) {
449                 goto out;
450         }
451
452         *service = SMB_STRDUP("ldap");
453         if (*service == NULL) {
454                 status = ADS_ERROR(LDAP_PARAM_ERROR);
455                 goto out;
456         }
457         *hostname = SMB_STRDUP(server);
458         if (*hostname == NULL) {
459                 SAFE_FREE(*service);
460                 status = ADS_ERROR(LDAP_PARAM_ERROR);
461                 goto out;
462         }
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;
469         }
470
471         *principal = princ;
472
473         status = ADS_SUCCESS;
474 out:
475         TALLOC_FREE(frame);
476         return status;
477 }
478
479 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
480                                                  struct ads_service_principal *p)
481 {
482         ADS_STATUS status;
483
484         ZERO_STRUCTP(p);
485
486         status = ads_guess_target(ads,
487                                   &p->service,
488                                   &p->hostname,
489                                   &p->string);
490         if (!ADS_ERR_OK(status)) {
491                 return status;
492         }
493
494         return ADS_SUCCESS;
495 }
496
497 #endif /* HAVE_KRB5 */
498
499 /*
500    this performs a SASL/SPNEGO bind
501 */
502 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
503 {
504         TALLOC_CTX *frame = talloc_stackframe();
505         struct ads_service_principal p = {0};
506         ADS_STATUS status;
507         const char *mech = NULL;
508
509         status = ads_generate_service_principal(ads, &p);
510         if (!ADS_ERR_OK(status)) {
511                 goto done;
512         }
513
514 #ifdef HAVE_KRB5
515         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
516             !is_ipaddress(p.hostname))
517         {
518                 mech = "KRB5";
519
520                 if (ads->auth.password == NULL ||
521                     ads->auth.password[0] == '\0')
522                 {
523
524                         status = ads_sasl_spnego_gensec_bind(ads,
525                                                              CRED_USE_KERBEROS_REQUIRED,
526                                                              p.service, p.hostname);
527                         if (ADS_ERR_OK(status)) {
528                                 ads_free_service_principal(&p);
529                                 goto done;
530                         }
531
532                         DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
533                                   "calling kinit\n", ads_errstr(status)));
534                 }
535
536                 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
537
538                 if (ADS_ERR_OK(status)) {
539                         status = ads_sasl_spnego_gensec_bind(ads,
540                                                         CRED_USE_KERBEROS_REQUIRED,
541                                                         p.service, p.hostname);
542                         if (!ADS_ERR_OK(status)) {
543                                 DBG_ERR("kinit succeeded but "
544                                         "SPNEGO bind with Kerberos failed "
545                                         "for %s/%s - user[%s], realm[%s]: %s\n",
546                                         p.service, p.hostname,
547                                         ads->auth.user_name,
548                                         ads->auth.realm,
549                                         ads_errstr(status));
550                         }
551                 }
552
553                 /* only fallback to NTLMSSP if allowed */
554                 if (ADS_ERR_OK(status) ||
555                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
556                         goto done;
557                 }
558
559                 DBG_WARNING("SASL bind with Kerberos failed "
560                             "for %s/%s - user[%s], realm[%s]: %s, "
561                             "try to fallback to NTLMSSP\n",
562                             p.service, p.hostname,
563                             ads->auth.user_name,
564                             ads->auth.realm,
565                             ads_errstr(status));
566         }
567 #endif
568
569         /* lets do NTLMSSP ... this has the big advantage that we don't need
570            to sync clocks, and we don't rely on special versions of the krb5
571            library for HMAC_MD4 encryption */
572         mech = "NTLMSSP";
573
574         if (!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
575                 DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
576                 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
577                 goto done;
578         }
579
580         if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
581                 DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
582                             " disallowed.\n");
583                 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
584                 goto done;
585         }
586
587         status = ads_sasl_spnego_gensec_bind(ads,
588                                              CRED_USE_KERBEROS_DISABLED,
589                                              p.service, p.hostname);
590 done:
591         if (!ADS_ERR_OK(status)) {
592                 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
593                          "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
594                           p.service, p.hostname,
595                           ads->auth.user_name,
596                           ads->auth.realm,
597                           ads_errstr(status)));
598         }
599         ads_free_service_principal(&p);
600         TALLOC_FREE(frame);
601         return status;
602 }
603
604 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
605 {
606         ADS_STATUS status;
607         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
608         bool tls = false;
609
610         if (ads->auth.flags & ADS_AUTH_SASL_LDAPS) {
611                 tls = true;
612                 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
613         } else if (ads->auth.flags & ADS_AUTH_SASL_STARTTLS) {
614                 tls = true;
615                 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
616         } else if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
617                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
618         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
619                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
620         } else {
621                 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
622         }
623
624         if (tls) {
625                 const DATA_BLOB *tls_cb = NULL;
626
627                 tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
628                 if (tls_cb == NULL) {
629                         DBG_ERR("No TLS channel bindings available\n");
630                         return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
631                 }
632         }
633
634 retry:
635         status = ads_sasl_spnego_bind(ads);
636         if (status.error_type == ENUM_ADS_ERROR_LDAP &&
637             status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
638             !tls &&
639             wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
640         {
641                 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
642                          "retrying with signing enabled\n"));
643                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
644                 goto retry;
645         }
646         return status;
647 }
648
649 #endif /* HAVE_LDAP */
650