Correctly check for errors in strlower_m() returns.
[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 "../libcli/auth/spnego.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
29 #ifdef HAVE_LDAP
30
31 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
32 {
33         struct gensec_security *gensec_security =
34                 talloc_get_type_abort(ads->ldap.wrap_private_data,
35                 struct gensec_security);
36         NTSTATUS nt_status;
37         DATA_BLOB unwrapped, wrapped;
38         TALLOC_CTX *frame = talloc_stackframe();
39
40         unwrapped = data_blob_const(buf, len);
41
42         nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
43         if (!NT_STATUS_IS_OK(nt_status)) {
44                 TALLOC_FREE(frame);
45                 return ADS_ERROR_NT(nt_status);
46         }
47
48         if ((ads->ldap.out.size - 4) < wrapped.length) {
49                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
50         }
51
52         /* copy the wrapped blob to the right location */
53         memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
54
55         /* set how many bytes must be written to the underlying socket */
56         ads->ldap.out.left = 4 + wrapped.length;
57
58         TALLOC_FREE(frame);
59
60         return ADS_SUCCESS;
61 }
62
63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
64 {
65         struct gensec_security *gensec_security =
66                 talloc_get_type_abort(ads->ldap.wrap_private_data,
67                 struct gensec_security);
68         NTSTATUS nt_status;
69         DATA_BLOB unwrapped, wrapped;
70         TALLOC_CTX *frame = talloc_stackframe();
71
72         wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
73
74         nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
75         if (!NT_STATUS_IS_OK(nt_status)) {
76                 TALLOC_FREE(frame);
77                 return ADS_ERROR_NT(nt_status);
78         }
79
80         if (wrapped.length < unwrapped.length) {
81                 TALLOC_FREE(frame);
82                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
83         }
84
85         /* copy the wrapped blob to the right location */
86         memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
87
88         /* set how many bytes must be written to the underlying socket */
89         ads->ldap.in.left       = unwrapped.length;
90         ads->ldap.in.ofs        = 4;
91
92         TALLOC_FREE(frame);
93
94         return ADS_SUCCESS;
95 }
96
97 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
98 {
99         struct gensec_security *gensec_security =
100                 talloc_get_type_abort(ads->ldap.wrap_private_data,
101                 struct gensec_security);
102
103         TALLOC_FREE(gensec_security);
104
105         ads->ldap.wrap_ops = NULL;
106         ads->ldap.wrap_private_data = NULL;
107 }
108
109 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
110         .name           = "ntlmssp",
111         .wrap           = ads_sasl_ntlmssp_wrap,
112         .unwrap         = ads_sasl_ntlmssp_unwrap,
113         .disconnect     = ads_sasl_ntlmssp_disconnect
114 };
115
116 /* 
117    perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
118    we fit on one socket??)
119 */
120 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
121 {
122         DATA_BLOB msg1 = data_blob_null;
123         DATA_BLOB blob = data_blob_null;
124         DATA_BLOB blob_in = data_blob_null;
125         DATA_BLOB blob_out = data_blob_null;
126         struct berval cred, *scred = NULL;
127         int rc;
128         NTSTATUS nt_status;
129         ADS_STATUS status;
130         int turn = 1;
131
132         struct auth_generic_state *auth_generic_state;
133
134         nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
135         if (!NT_STATUS_IS_OK(nt_status)) {
136                 return ADS_ERROR_NT(nt_status);
137         }
138
139         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
140                 return ADS_ERROR_NT(nt_status);
141         }
142         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
143                 return ADS_ERROR_NT(nt_status);
144         }
145         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
146                 return ADS_ERROR_NT(nt_status);
147         }
148
149         switch (ads->ldap.wrap_type) {
150         case ADS_SASLWRAP_TYPE_SEAL:
151                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
152                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
153                 break;
154         case ADS_SASLWRAP_TYPE_SIGN:
155                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
156                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
157                 } else {
158                         /*
159                          * windows servers are broken with sign only,
160                          * so we need to use seal here too
161                          */
162                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
163                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
164                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
165                 }
166                 break;
167         case ADS_SASLWRAP_TYPE_PLAIN:
168                 break;
169         }
170
171         nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
172         if (!NT_STATUS_IS_OK(nt_status)) {
173                 return ADS_ERROR_NT(nt_status);
174         }
175
176         blob_in = data_blob_null;
177
178         do {
179                 nt_status = gensec_update(auth_generic_state->gensec_security,
180                                           talloc_tos(), NULL, blob_in, &blob_out);
181                 data_blob_free(&blob_in);
182                 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 
183                      || NT_STATUS_IS_OK(nt_status))
184                     && blob_out.length) {
185                         if (turn == 1) {
186                                 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
187                                 /* and wrap it in a SPNEGO wrapper */
188                                 msg1 = spnego_gen_negTokenInit(talloc_tos(),
189                                                 OIDs_ntlm, &blob_out, NULL);
190                         } else {
191                                 /* wrap it in SPNEGO */
192                                 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
193                         }
194
195                         data_blob_free(&blob_out);
196
197                         cred.bv_val = (char *)msg1.data;
198                         cred.bv_len = msg1.length;
199                         scred = NULL;
200                         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
201                         data_blob_free(&msg1);
202                         if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
203                                 if (scred) {
204                                         ber_bvfree(scred);
205                                 }
206
207                                 TALLOC_FREE(auth_generic_state);
208                                 return ADS_ERROR(rc);
209                         }
210                         if (scred) {
211                                 blob = data_blob(scred->bv_val, scred->bv_len);
212                                 ber_bvfree(scred);
213                         } else {
214                                 blob = data_blob_null;
215                         }
216
217                 } else {
218
219                         TALLOC_FREE(auth_generic_state);
220                         data_blob_free(&blob_out);
221                         return ADS_ERROR_NT(nt_status);
222                 }
223                 
224                 if ((turn == 1) && 
225                     (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
226                         DATA_BLOB tmp_blob = data_blob_null;
227                         /* the server might give us back two challenges */
228                         if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in, 
229                                                     &tmp_blob)) {
230
231                                 TALLOC_FREE(auth_generic_state);
232                                 data_blob_free(&blob);
233                                 DEBUG(3,("Failed to parse challenges\n"));
234                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
235                         }
236                         data_blob_free(&tmp_blob);
237                 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
238                         if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP, 
239                                                         &blob_in)) {
240
241                                 TALLOC_FREE(auth_generic_state);
242                                 data_blob_free(&blob);
243                                 DEBUG(3,("Failed to parse auth response\n"));
244                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
245                         }
246                 }
247                 data_blob_free(&blob);
248                 data_blob_free(&blob_out);
249                 turn++;
250         } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
251         
252         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
253                 uint32_t sig_size = gensec_sig_size(auth_generic_state->gensec_security, 0);
254                 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - sig_size;
255                 ads->ldap.out.sig_size = sig_size;
256                 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
257                 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
258                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
259                 if (!ADS_ERR_OK(status)) {
260                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
261                                 ads_errstr(status)));
262                         TALLOC_FREE(auth_generic_state);
263                         return status;
264                 }
265                 /* Only keep the gensec_security element around long-term */
266                 talloc_steal(NULL, auth_generic_state->gensec_security);
267         }
268         TALLOC_FREE(auth_generic_state);
269
270         return ADS_ERROR(rc);
271 }
272
273 #ifdef HAVE_KRB5
274 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
275 {
276         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
277         ADS_STATUS status;
278         int gss_rc;
279         uint32 minor_status;
280         gss_buffer_desc unwrapped, wrapped;
281         int conf_req_flag, conf_state;
282
283         unwrapped.value         = buf;
284         unwrapped.length        = len;
285
286         /* for now request sign and seal */
287         conf_req_flag   = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
288
289         gss_rc = gss_wrap(&minor_status, context_handle,
290                           conf_req_flag, GSS_C_QOP_DEFAULT,
291                           &unwrapped, &conf_state,
292                           &wrapped);
293         status = ADS_ERROR_GSS(gss_rc, minor_status);
294         if (!ADS_ERR_OK(status)) return status;
295
296         if (conf_req_flag && conf_state == 0) {
297                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
298         }
299
300         if ((ads->ldap.out.size - 4) < wrapped.length) {
301                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
302         }
303
304         /* copy the wrapped blob to the right location */
305         memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
306
307         /* set how many bytes must be written to the underlying socket */
308         ads->ldap.out.left = 4 + wrapped.length;
309
310         gss_release_buffer(&minor_status, &wrapped);
311
312         return ADS_SUCCESS;
313 }
314
315 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
316 {
317         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
318         ADS_STATUS status;
319         int gss_rc;
320         uint32 minor_status;
321         gss_buffer_desc unwrapped, wrapped;
322         int conf_state;
323
324         wrapped.value   = ads->ldap.in.buf + 4;
325         wrapped.length  = ads->ldap.in.ofs - 4;
326
327         gss_rc = gss_unwrap(&minor_status, context_handle,
328                             &wrapped, &unwrapped,
329                             &conf_state, GSS_C_QOP_DEFAULT);
330         status = ADS_ERROR_GSS(gss_rc, minor_status);
331         if (!ADS_ERR_OK(status)) return status;
332
333         if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
334                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
335         }
336
337         if (wrapped.length < unwrapped.length) {
338                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
339         }
340
341         /* copy the wrapped blob to the right location */
342         memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
343
344         /* set how many bytes must be written to the underlying socket */
345         ads->ldap.in.left       = unwrapped.length;
346         ads->ldap.in.ofs        = 4;
347
348         gss_release_buffer(&minor_status, &unwrapped);
349
350         return ADS_SUCCESS;
351 }
352
353 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
354 {
355         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
356         uint32 minor_status;
357
358         gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
359
360         ads->ldap.wrap_ops = NULL;
361         ads->ldap.wrap_private_data = NULL;
362 }
363
364 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
365         .name           = "gssapi",
366         .wrap           = ads_sasl_gssapi_wrap,
367         .unwrap         = ads_sasl_gssapi_unwrap,
368         .disconnect     = ads_sasl_gssapi_disconnect
369 };
370
371 /* 
372    perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
373 */
374 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
375 {
376         ADS_STATUS status;
377         bool ok;
378         uint32 minor_status;
379         int gss_rc, rc;
380         gss_OID_desc krb5_mech_type =
381         {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
382         gss_OID mech_type = &krb5_mech_type;
383         gss_OID actual_mech_type = GSS_C_NULL_OID;
384         const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
385         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
386         gss_buffer_desc input_token, output_token;
387         uint32 req_flags, ret_flags;
388         uint32 req_tmp, ret_tmp;
389         DATA_BLOB unwrapped;
390         DATA_BLOB wrapped;
391         struct berval cred, *scred = NULL;
392
393         input_token.value = NULL;
394         input_token.length = 0;
395
396         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
397         switch (ads->ldap.wrap_type) {
398         case ADS_SASLWRAP_TYPE_SEAL:
399                 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
400                 break;
401         case ADS_SASLWRAP_TYPE_SIGN:
402                 req_flags |= GSS_C_INTEG_FLAG;
403                 break;
404         case ADS_SASLWRAP_TYPE_PLAIN:
405                 break;
406         }
407
408         /* Note: here we explicit ask for the krb5 mech_type */
409         gss_rc = gss_init_sec_context(&minor_status,
410                                       GSS_C_NO_CREDENTIAL,
411                                       &context_handle,
412                                       serv_name,
413                                       mech_type,
414                                       req_flags,
415                                       0,
416                                       NULL,
417                                       &input_token,
418                                       &actual_mech_type,
419                                       &output_token,
420                                       &ret_flags,
421                                       NULL);
422         if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
423                 status = ADS_ERROR_GSS(gss_rc, minor_status);
424                 goto failed;
425         }
426
427         /*
428          * As some gssapi krb5 mech implementations
429          * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
430          * to req_flags internaly, it's not possible to
431          * use plain or signing only connection via
432          * the gssapi interface.
433          *
434          * Because of this we need to check it the ret_flags
435          * has more flags as req_flags and correct the value
436          * of ads->ldap.wrap_type.
437          *
438          * I ads->auth.flags has ADS_AUTH_SASL_FORCE
439          * we need to give an error.
440          */
441         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
442         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
443
444         if (req_tmp == ret_tmp) {
445                 /* everythings fine... */
446
447         } else if (req_flags & GSS_C_CONF_FLAG) {
448                 /*
449                  * here we wanted sealing but didn't got it
450                  * from the gssapi library
451                  */
452                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
453                 goto failed;
454
455         } else if ((req_flags & GSS_C_INTEG_FLAG) &&
456                    !(ret_flags & GSS_C_INTEG_FLAG)) {
457                 /*
458                  * here we wanted siging but didn't got it
459                  * from the gssapi library
460                  */
461                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
462                 goto failed;
463
464         } else if (ret_flags & GSS_C_CONF_FLAG) {
465                 /*
466                  * here we didn't want sealing
467                  * but the gssapi library forces it
468                  * so correct the needed wrap_type if
469                  * the caller didn't forced siging only
470                  */
471                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
472                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
473                         goto failed;
474                 }
475
476                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
477                 req_flags = ret_flags;
478
479         } else if (ret_flags & GSS_C_INTEG_FLAG) {
480                 /*
481                  * here we didn't want signing
482                  * but the gssapi library forces it
483                  * so correct the needed wrap_type if
484                  * the caller didn't forced plain
485                  */
486                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
487                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
488                         goto failed;
489                 }
490
491                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
492                 req_flags = ret_flags;
493         } else {
494                 /*
495                  * This could (should?) not happen
496                  */
497                 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
498                 goto failed;
499         
500         }
501
502         /* and wrap that in a shiny SPNEGO wrapper */
503         unwrapped = data_blob_const(output_token.value, output_token.length);
504         wrapped = spnego_gen_negTokenInit(talloc_tos(),
505                         spnego_mechs, &unwrapped, NULL);
506         gss_release_buffer(&minor_status, &output_token);
507         if (unwrapped.length > wrapped.length) {
508                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
509                 goto failed;
510         }
511
512         cred.bv_val = (char *)wrapped.data;
513         cred.bv_len = wrapped.length;
514
515         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, 
516                               &scred);
517         data_blob_free(&wrapped);
518         if (rc != LDAP_SUCCESS) {
519                 status = ADS_ERROR(rc);
520                 goto failed;
521         }
522
523         if (scred) {
524                 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
525         } else {
526                 wrapped = data_blob_null;
527         }
528
529         ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
530                                         OID_KERBEROS5_OLD,
531                                         &unwrapped);
532         if (scred) ber_bvfree(scred);
533         if (!ok) {
534                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
535                 goto failed;
536         }
537
538         input_token.value       = unwrapped.data;
539         input_token.length      = unwrapped.length;
540
541         /* 
542          * As we asked for mutal authentication
543          * we need to pass the servers response
544          * to gssapi
545          */
546         gss_rc = gss_init_sec_context(&minor_status,
547                                       GSS_C_NO_CREDENTIAL,
548                                       &context_handle,
549                                       serv_name,
550                                       mech_type,
551                                       req_flags,
552                                       0,
553                                       NULL,
554                                       &input_token,
555                                       &actual_mech_type,
556                                       &output_token,
557                                       &ret_flags,
558                                       NULL);
559         data_blob_free(&unwrapped);
560         if (gss_rc) {
561                 status = ADS_ERROR_GSS(gss_rc, minor_status);
562                 goto failed;
563         }
564
565         gss_release_buffer(&minor_status, &output_token);
566
567         /*
568          * If we the sign and seal options
569          * doesn't match after getting the response
570          * from the server, we don't want to use the connection
571          */
572         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
573         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
574
575         if (req_tmp != ret_tmp) {
576                 /* everythings fine... */
577                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
578                 goto failed;
579         }
580
581         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
582                 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
583
584                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
585                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
586                                              GSS_C_QOP_DEFAULT,
587                                              max_msg_size, &ads->ldap.out.max_unwrapped);
588                 if (gss_rc) {
589                         status = ADS_ERROR_GSS(gss_rc, minor_status);
590                         goto failed;
591                 }
592
593                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
594                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
595                 ads->ldap.in.max_wrapped = max_msg_size;
596                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
597                 if (!ADS_ERR_OK(status)) {
598                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
599                                 ads_errstr(status)));
600                         goto failed;
601                 }
602                 /* make sure we don't free context_handle */
603                 context_handle = GSS_C_NO_CONTEXT;
604         }
605
606         status = ADS_SUCCESS;
607
608 failed:
609         if (context_handle != GSS_C_NO_CONTEXT)
610                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
611         return status;
612 }
613
614 #endif /* HAVE_KRB5 */
615
616 #ifdef HAVE_KRB5
617 struct ads_service_principal {
618          char *string;
619 #ifdef HAVE_KRB5
620          gss_name_t name;
621 #endif
622 };
623
624 static void ads_free_service_principal(struct ads_service_principal *p)
625 {
626         SAFE_FREE(p->string);
627
628 #ifdef HAVE_KRB5
629         if (p->name) {
630                 uint32 minor_status;
631                 gss_release_name(&minor_status, &p->name);
632         }
633 #endif
634         ZERO_STRUCTP(p);
635 }
636
637
638 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
639                                               char **returned_principal)
640 {
641         char *princ = NULL;
642
643         if (ads->server.realm && ads->server.ldap_server) {
644                 char *server, *server_realm;
645
646                 server = SMB_STRDUP(ads->server.ldap_server);
647                 server_realm = SMB_STRDUP(ads->server.realm);
648
649                 if (!server || !server_realm) {
650                         SAFE_FREE(server);
651                         SAFE_FREE(server_realm);
652                         return ADS_ERROR(LDAP_NO_MEMORY);
653                 }
654
655                 if (!strlower_m(server)) {
656                         SAFE_FREE(server);
657                         SAFE_FREE(server_realm);
658                         return ADS_ERROR(LDAP_NO_MEMORY);
659                 }
660
661                 if (!strupper_m(server_realm)) {
662                         SAFE_FREE(server);
663                         SAFE_FREE(server_realm);
664                         return ADS_ERROR(LDAP_NO_MEMORY);
665                 }
666
667                 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
668                         SAFE_FREE(server);
669                         SAFE_FREE(server_realm);
670                         return ADS_ERROR(LDAP_NO_MEMORY);
671                 }
672
673                 SAFE_FREE(server);
674                 SAFE_FREE(server_realm);
675
676                 if (!princ) {
677                         return ADS_ERROR(LDAP_NO_MEMORY);
678                 }
679         } else if (ads->config.realm && ads->config.ldap_server_name) {
680                 char *server, *server_realm;
681
682                 server = SMB_STRDUP(ads->config.ldap_server_name);
683                 server_realm = SMB_STRDUP(ads->config.realm);
684
685                 if (!server || !server_realm) {
686                         SAFE_FREE(server);
687                         SAFE_FREE(server_realm);
688                         return ADS_ERROR(LDAP_NO_MEMORY);
689                 }
690
691                 if (!strlower_m(server)) {
692                         SAFE_FREE(server);
693                         SAFE_FREE(server_realm);
694                         return ADS_ERROR(LDAP_NO_MEMORY);
695                 }
696
697                 if (!strupper_m(server_realm)) {
698                         SAFE_FREE(server);
699                         SAFE_FREE(server_realm);
700                         return ADS_ERROR(LDAP_NO_MEMORY);
701                 }
702                 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
703                         SAFE_FREE(server);
704                         SAFE_FREE(server_realm);
705                         return ADS_ERROR(LDAP_NO_MEMORY);
706                 }
707
708                 SAFE_FREE(server);
709                 SAFE_FREE(server_realm);
710
711                 if (!princ) {
712                         return ADS_ERROR(LDAP_NO_MEMORY);
713                 }
714         }
715
716         if (!princ) {
717                 return ADS_ERROR(LDAP_PARAM_ERROR);
718         }
719
720         *returned_principal = princ;
721
722         return ADS_SUCCESS;
723 }
724
725 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
726                                                  const char *given_principal,
727                                                  struct ads_service_principal *p)
728 {
729         ADS_STATUS status;
730 #ifdef HAVE_KRB5
731         gss_buffer_desc input_name;
732         /* GSS_KRB5_NT_PRINCIPAL_NAME */
733         gss_OID_desc nt_principal =
734         {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
735         uint32 minor_status;
736         int gss_rc;
737 #endif
738
739         ZERO_STRUCTP(p);
740
741         /* I've seen a child Windows 2000 domain not send
742            the principal name back in the first round of
743            the SASL bind reply.  So we guess based on server
744            name and realm.  --jerry  */
745         /* Also try best guess when we get the w2k8 ignore principal
746            back, or when we are configured to ignore it - gd,
747            abartlet */
748
749         if (!lp_client_use_spnego_principal() ||
750             !given_principal ||
751             strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
752
753                 status = ads_guess_service_principal(ads, &p->string);
754                 if (!ADS_ERR_OK(status)) {
755                         return status;
756                 }
757         } else {
758                 p->string = SMB_STRDUP(given_principal);
759                 if (!p->string) {
760                         return ADS_ERROR(LDAP_NO_MEMORY);
761                 }
762         }
763
764 #ifdef HAVE_KRB5
765         input_name.value = p->string;
766         input_name.length = strlen(p->string);
767
768         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
769         if (gss_rc) {
770                 ads_free_service_principal(p);
771                 return ADS_ERROR_GSS(gss_rc, minor_status);
772         }
773 #endif
774
775         return ADS_SUCCESS;
776 }
777
778 /* 
779    perform a LDAP/SASL/SPNEGO/KRB5 bind
780 */
781 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
782 {
783         DATA_BLOB blob = data_blob_null;
784         struct berval cred, *scred = NULL;
785         DATA_BLOB session_key = data_blob_null;
786         int rc;
787
788         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
789                 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
790         }
791
792         rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
793                                      ads->auth.time_offset, &blob, &session_key, 0,
794                                      &ads->auth.tgs_expire);
795
796         if (rc) {
797                 return ADS_ERROR_KRB5(rc);
798         }
799
800         /* now send the auth packet and we should be done */
801         cred.bv_val = (char *)blob.data;
802         cred.bv_len = blob.length;
803
804         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
805
806         data_blob_free(&blob);
807         data_blob_free(&session_key);
808         if(scred)
809                 ber_bvfree(scred);
810
811         return ADS_ERROR(rc);
812 }
813
814 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
815                                             struct ads_service_principal *p)
816 {
817 #ifdef HAVE_KRB5
818         /*
819          * we only use the gsskrb5 based implementation
820          * when sasl sign or seal is requested.
821          *
822          * This has the following reasons:
823          * - it's likely that the gssapi krb5 mech implementation
824          *   doesn't support to negotiate plain connections
825          * - the ads_sasl_spnego_rawkrb5_bind is more robust
826          *   against clock skew errors
827          */
828         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
829                 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
830         }
831 #endif
832         return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
833 }
834 #endif /* HAVE_KRB5 */
835
836 /* 
837    this performs a SASL/SPNEGO bind
838 */
839 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
840 {
841         struct berval *scred=NULL;
842         int rc, i;
843         ADS_STATUS status;
844         DATA_BLOB blob;
845         char *given_principal = NULL;
846         char *OIDs[ASN1_MAX_OIDS];
847 #ifdef HAVE_KRB5
848         bool got_kerberos_mechanism = False;
849 #endif
850
851         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
852
853         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
854                 status = ADS_ERROR(rc);
855                 goto failed;
856         }
857
858         blob = data_blob(scred->bv_val, scred->bv_len);
859
860         ber_bvfree(scred);
861
862 #if 0
863         file_save("sasl_spnego.dat", blob.data, blob.length);
864 #endif
865
866         /* the server sent us the first part of the SPNEGO exchange in the negprot 
867            reply */
868         if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
869                         OIDs[0] == NULL) {
870                 data_blob_free(&blob);
871                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
872                 goto failed;
873         }
874         data_blob_free(&blob);
875
876         /* make sure the server understands kerberos */
877         for (i=0;OIDs[i];i++) {
878                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
879 #ifdef HAVE_KRB5
880                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
881                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
882                         got_kerberos_mechanism = True;
883                 }
884 #endif
885                 talloc_free(OIDs[i]);
886         }
887         DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
888
889 #ifdef HAVE_KRB5
890         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
891             got_kerberos_mechanism) 
892         {
893                 struct ads_service_principal p;
894
895                 status = ads_generate_service_principal(ads, given_principal, &p);
896                 TALLOC_FREE(given_principal);
897                 if (!ADS_ERR_OK(status)) {
898                         return status;
899                 }
900
901                 status = ads_sasl_spnego_krb5_bind(ads, &p);
902                 if (ADS_ERR_OK(status)) {
903                         ads_free_service_principal(&p);
904                         return status;
905                 }
906
907                 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
908                           "calling kinit\n", ads_errstr(status)));
909
910                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
911
912                 if (ADS_ERR_OK(status)) {
913                         status = ads_sasl_spnego_krb5_bind(ads, &p);
914                         if (!ADS_ERR_OK(status)) {
915                                 DEBUG(0,("kinit succeeded but "
916                                         "ads_sasl_spnego_krb5_bind failed: %s\n",
917                                         ads_errstr(status)));
918                         }
919                 }
920
921                 ads_free_service_principal(&p);
922
923                 /* only fallback to NTLMSSP if allowed */
924                 if (ADS_ERR_OK(status) || 
925                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
926                         return status;
927                 }
928         } else
929 #endif
930         {
931                 TALLOC_FREE(given_principal);
932         }
933
934         /* lets do NTLMSSP ... this has the big advantage that we don't need
935            to sync clocks, and we don't rely on special versions of the krb5 
936            library for HMAC_MD4 encryption */
937         return ads_sasl_spnego_ntlmssp_bind(ads);
938
939 failed:
940         return status;
941 }
942
943 #ifdef HAVE_KRB5
944 #define MAX_GSS_PASSES 3
945
946 /* this performs a SASL/gssapi bind
947    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
948    is very dependent on correctly configured DNS whereas
949    this routine is much less fragile
950    see RFC2078 and RFC2222 for details
951 */
952 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
953 {
954         uint32 minor_status;
955         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
956         gss_OID mech_type = GSS_C_NULL_OID;
957         gss_buffer_desc output_token, input_token;
958         uint32 req_flags, ret_flags;
959         int conf_state;
960         struct berval cred;
961         struct berval *scred = NULL;
962         int i=0;
963         int gss_rc, rc;
964         uint8 *p;
965         uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
966         uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
967         ADS_STATUS status;
968
969         input_token.value = NULL;
970         input_token.length = 0;
971
972         /*
973          * Note: here we always ask the gssapi for sign and seal
974          *       as this is negotiated later after the mutal
975          *       authentication
976          */
977         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
978
979         for (i=0; i < MAX_GSS_PASSES; i++) {
980                 gss_rc = gss_init_sec_context(&minor_status,
981                                           GSS_C_NO_CREDENTIAL,
982                                           &context_handle,
983                                           serv_name,
984                                           mech_type,
985                                           req_flags,
986                                           0,
987                                           NULL,
988                                           &input_token,
989                                           NULL,
990                                           &output_token,
991                                           &ret_flags,
992                                           NULL);
993                 if (scred) {
994                         ber_bvfree(scred);
995                         scred = NULL;
996                 }
997                 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
998                         status = ADS_ERROR_GSS(gss_rc, minor_status);
999                         goto failed;
1000                 }
1001
1002                 cred.bv_val = (char *)output_token.value;
1003                 cred.bv_len = output_token.length;
1004
1005                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
1006                                       &scred);
1007                 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
1008                         status = ADS_ERROR(rc);
1009                         goto failed;
1010                 }
1011
1012                 if (output_token.value) {
1013                         gss_release_buffer(&minor_status, &output_token);
1014                 }
1015
1016                 if (scred) {
1017                         input_token.value = scred->bv_val;
1018                         input_token.length = scred->bv_len;
1019                 } else {
1020                         input_token.value = NULL;
1021                         input_token.length = 0;
1022                 }
1023
1024                 if (gss_rc == 0) break;
1025         }
1026
1027         gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1028                             &conf_state,NULL);
1029         if (scred) {
1030                 ber_bvfree(scred);
1031                 scred = NULL;
1032         }
1033         if (gss_rc) {
1034                 status = ADS_ERROR_GSS(gss_rc, minor_status);
1035                 goto failed;
1036         }
1037
1038         p = (uint8 *)output_token.value;
1039
1040 #if 0
1041         file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1042 #endif
1043
1044         if (p) {
1045                 wrap_type = CVAL(p,0);
1046                 SCVAL(p,0,0);
1047                 max_msg_size = RIVAL(p,0);
1048         }
1049
1050         gss_release_buffer(&minor_status, &output_token);
1051
1052         if (!(wrap_type & ads->ldap.wrap_type)) {
1053                 /*
1054                  * the server doesn't supports the wrap
1055                  * type we want :-(
1056                  */
1057                 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1058                         ads->ldap.wrap_type, wrap_type));
1059                 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1060                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1061                 goto failed;
1062         }
1063
1064         /* 0x58 is the minimum windows accepts */
1065         if (max_msg_size < 0x58) {
1066                 max_msg_size = 0x58;
1067         }
1068
1069         output_token.length = 4;
1070         output_token.value = SMB_MALLOC(output_token.length);
1071         if (!output_token.value) {
1072                 output_token.length = 0;
1073                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1074                 goto failed;
1075         }
1076         p = (uint8 *)output_token.value;
1077
1078         RSIVAL(p,0,max_msg_size);
1079         SCVAL(p,0,ads->ldap.wrap_type);
1080
1081         /*
1082          * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1083          * but using ads->config.bind_path is the wrong! It should be
1084          * the DN of the user object!
1085          *
1086          * w2k3 gives an error when we send an incorrect DN, but sending nothing
1087          * is ok and matches the information flow used in GSS-SPNEGO.
1088          */
1089
1090         gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1091                         &output_token, /* used as *input* here. */
1092                         &conf_state,
1093                         &input_token); /* Used as *output* here. */
1094         if (gss_rc) {
1095                 status = ADS_ERROR_GSS(gss_rc, minor_status);
1096                 output_token.length = 0;
1097                 SAFE_FREE(output_token.value);
1098                 goto failed;
1099         }
1100
1101         /* We've finished with output_token. */
1102         SAFE_FREE(output_token.value);
1103         output_token.length = 0;
1104
1105         cred.bv_val = (char *)input_token.value;
1106         cred.bv_len = input_token.length;
1107
1108         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
1109                               &scred);
1110         gss_release_buffer(&minor_status, &input_token);
1111         status = ADS_ERROR(rc);
1112         if (!ADS_ERR_OK(status)) {
1113                 goto failed;
1114         }
1115
1116         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1117                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1118                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1119                                              GSS_C_QOP_DEFAULT,
1120                                              max_msg_size, &ads->ldap.out.max_unwrapped);
1121                 if (gss_rc) {
1122                         status = ADS_ERROR_GSS(gss_rc, minor_status);
1123                         goto failed;
1124                 }
1125
1126                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1127                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1128                 ads->ldap.in.max_wrapped = max_msg_size;
1129                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1130                 if (!ADS_ERR_OK(status)) {
1131                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1132                                 ads_errstr(status)));
1133                         goto failed;
1134                 }
1135                 /* make sure we don't free context_handle */
1136                 context_handle = GSS_C_NO_CONTEXT;
1137         }
1138
1139 failed:
1140
1141         if (context_handle != GSS_C_NO_CONTEXT)
1142                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1143
1144         if(scred)
1145                 ber_bvfree(scred);
1146         return status;
1147 }
1148
1149 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1150 {
1151         ADS_STATUS status;
1152         struct ads_service_principal p;
1153
1154         status = ads_generate_service_principal(ads, NULL, &p);
1155         if (!ADS_ERR_OK(status)) {
1156                 return status;
1157         }
1158
1159         status = ads_sasl_gssapi_do_bind(ads, p.name);
1160         if (ADS_ERR_OK(status)) {
1161                 ads_free_service_principal(&p);
1162                 return status;
1163         }
1164
1165         DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1166                   "calling kinit\n", ads_errstr(status)));
1167
1168         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1169
1170         if (ADS_ERR_OK(status)) {
1171                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1172         }
1173
1174         ads_free_service_principal(&p);
1175
1176         return status;
1177 }
1178
1179 #endif /* HAVE_KRB5 */
1180
1181 /* mapping between SASL mechanisms and functions */
1182 static struct {
1183         const char *name;
1184         ADS_STATUS (*fn)(ADS_STRUCT *);
1185 } sasl_mechanisms[] = {
1186         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1187 #ifdef HAVE_KRB5
1188         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1189 #endif
1190         {NULL, NULL}
1191 };
1192
1193 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1194 {
1195         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1196         char **values;
1197         ADS_STATUS status;
1198         int i, j;
1199         LDAPMessage *res;
1200
1201         /* get a list of supported SASL mechanisms */
1202         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1203         if (!ADS_ERR_OK(status)) return status;
1204
1205         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1206
1207         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1208                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1209         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1210                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1211         } else {
1212                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1213         }
1214
1215         /* try our supported mechanisms in order */
1216         for (i=0;sasl_mechanisms[i].name;i++) {
1217                 /* see if the server supports it */
1218                 for (j=0;values && values[j];j++) {
1219                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1220                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1221 retry:
1222                                 status = sasl_mechanisms[i].fn(ads);
1223                                 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1224                                     status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1225                                     ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1226                                 {
1227                                         DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1228                                                  "retrying with signing enabled\n"));
1229                                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1230                                         goto retry;
1231                                 }
1232                                 ldap_value_free(values);
1233                                 ldap_msgfree(res);
1234                                 return status;
1235                         }
1236                 }
1237         }
1238
1239         ldap_value_free(values);
1240         ldap_msgfree(res);
1241         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1242 }
1243
1244 #endif /* HAVE_LDAP */
1245