dns: Use new DNS debugclass in DNS server
[kai/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_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
275 {
276         ADS_STATUS status;
277         krb5_context kctx;
278         krb5_error_code kerr;
279         krb5_ccache kccache = NULL;
280         uint32_t maj, min;
281
282         *cred = GSS_C_NO_CREDENTIAL;
283
284         if (!ads->auth.ccache_name) {
285                 return ADS_SUCCESS;
286         }
287
288         kerr = krb5_init_context(&kctx);
289         if (kerr) {
290                 return ADS_ERROR_KRB5(kerr);
291         }
292
293 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
294         kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
295         if (kerr) {
296                 status = ADS_ERROR_KRB5(kerr);
297                 goto done;
298         }
299
300         maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
301         if (maj != GSS_S_COMPLETE) {
302                 status = ADS_ERROR_GSS(maj, min);
303                 goto done;
304         }
305 #else
306         /* We need to fallback to overriding the default creds.
307          * This operation is not thread safe as it changes the process
308          * environment variable, but we do not have any better option
309          * with older kerberos libraries */
310         {
311                 const char *oldccname = NULL;
312
313                 oldccname = getenv("KRB5CCNAME");
314                 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
315
316                 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
317                                        NULL, GSS_C_INITIATE, cred, NULL, NULL);
318
319                 if (oldccname) {
320                         setenv("KRB5CCNAME", oldccname, 1);
321                 } else {
322                         unsetenv("KRB5CCNAME");
323                 }
324
325                 if (maj != GSS_S_COMPLETE) {
326                         status = ADS_ERROR_GSS(maj, min);
327                         goto done;
328                 }
329         }
330 #endif
331
332         status = ADS_SUCCESS;
333
334 done:
335         if (!ADS_ERR_OK(status) && kccache != NULL) {
336                 krb5_cc_close(kctx, kccache);
337         }
338         krb5_free_context(kctx);
339         return status;
340 }
341
342 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
343 {
344         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
345         ADS_STATUS status;
346         int gss_rc;
347         uint32 minor_status;
348         gss_buffer_desc unwrapped, wrapped;
349         int conf_req_flag, conf_state;
350
351         unwrapped.value         = buf;
352         unwrapped.length        = len;
353
354         /* for now request sign and seal */
355         conf_req_flag   = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
356
357         gss_rc = gss_wrap(&minor_status, context_handle,
358                           conf_req_flag, GSS_C_QOP_DEFAULT,
359                           &unwrapped, &conf_state,
360                           &wrapped);
361         status = ADS_ERROR_GSS(gss_rc, minor_status);
362         if (!ADS_ERR_OK(status)) return status;
363
364         if (conf_req_flag && conf_state == 0) {
365                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
366         }
367
368         if ((ads->ldap.out.size - 4) < wrapped.length) {
369                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
370         }
371
372         /* copy the wrapped blob to the right location */
373         memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
374
375         /* set how many bytes must be written to the underlying socket */
376         ads->ldap.out.left = 4 + wrapped.length;
377
378         gss_release_buffer(&minor_status, &wrapped);
379
380         return ADS_SUCCESS;
381 }
382
383 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
384 {
385         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
386         ADS_STATUS status;
387         int gss_rc;
388         uint32 minor_status;
389         gss_buffer_desc unwrapped, wrapped;
390         int conf_state;
391
392         wrapped.value   = ads->ldap.in.buf + 4;
393         wrapped.length  = ads->ldap.in.ofs - 4;
394
395         gss_rc = gss_unwrap(&minor_status, context_handle,
396                             &wrapped, &unwrapped,
397                             &conf_state, GSS_C_QOP_DEFAULT);
398         status = ADS_ERROR_GSS(gss_rc, minor_status);
399         if (!ADS_ERR_OK(status)) return status;
400
401         if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
402                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
403         }
404
405         if (wrapped.length < unwrapped.length) {
406                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
407         }
408
409         /* copy the wrapped blob to the right location */
410         memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
411
412         /* set how many bytes must be written to the underlying socket */
413         ads->ldap.in.left       = unwrapped.length;
414         ads->ldap.in.ofs        = 4;
415
416         gss_release_buffer(&minor_status, &unwrapped);
417
418         return ADS_SUCCESS;
419 }
420
421 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
422 {
423         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
424         uint32 minor_status;
425
426         gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
427
428         ads->ldap.wrap_ops = NULL;
429         ads->ldap.wrap_private_data = NULL;
430 }
431
432 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
433         .name           = "gssapi",
434         .wrap           = ads_sasl_gssapi_wrap,
435         .unwrap         = ads_sasl_gssapi_unwrap,
436         .disconnect     = ads_sasl_gssapi_disconnect
437 };
438
439 /* 
440    perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
441 */
442 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
443 {
444         ADS_STATUS status;
445         bool ok;
446         uint32 minor_status;
447         int gss_rc, rc;
448         gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
449         gss_OID_desc krb5_mech_type =
450         {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
451         gss_OID mech_type = &krb5_mech_type;
452         gss_OID actual_mech_type = GSS_C_NULL_OID;
453         const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
454         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
455         gss_buffer_desc input_token, output_token;
456         uint32 req_flags, ret_flags;
457         uint32 req_tmp, ret_tmp;
458         DATA_BLOB unwrapped;
459         DATA_BLOB wrapped;
460         struct berval cred, *scred = NULL;
461
462         status = ads_init_gssapi_cred(ads, &gss_cred);
463         if (!ADS_ERR_OK(status)) {
464                 goto failed;
465         }
466
467         input_token.value = NULL;
468         input_token.length = 0;
469
470         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
471         switch (ads->ldap.wrap_type) {
472         case ADS_SASLWRAP_TYPE_SEAL:
473                 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
474                 break;
475         case ADS_SASLWRAP_TYPE_SIGN:
476                 req_flags |= GSS_C_INTEG_FLAG;
477                 break;
478         case ADS_SASLWRAP_TYPE_PLAIN:
479                 break;
480         }
481
482         /* Note: here we explicit ask for the krb5 mech_type */
483         gss_rc = gss_init_sec_context(&minor_status,
484                                       gss_cred,
485                                       &context_handle,
486                                       serv_name,
487                                       mech_type,
488                                       req_flags,
489                                       0,
490                                       NULL,
491                                       &input_token,
492                                       &actual_mech_type,
493                                       &output_token,
494                                       &ret_flags,
495                                       NULL);
496         if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
497                 status = ADS_ERROR_GSS(gss_rc, minor_status);
498                 goto failed;
499         }
500
501         /*
502          * As some gssapi krb5 mech implementations
503          * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
504          * to req_flags internaly, it's not possible to
505          * use plain or signing only connection via
506          * the gssapi interface.
507          *
508          * Because of this we need to check it the ret_flags
509          * has more flags as req_flags and correct the value
510          * of ads->ldap.wrap_type.
511          *
512          * I ads->auth.flags has ADS_AUTH_SASL_FORCE
513          * we need to give an error.
514          */
515         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
516         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
517
518         if (req_tmp == ret_tmp) {
519                 /* everythings fine... */
520
521         } else if (req_flags & GSS_C_CONF_FLAG) {
522                 /*
523                  * here we wanted sealing but didn't got it
524                  * from the gssapi library
525                  */
526                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
527                 goto failed;
528
529         } else if ((req_flags & GSS_C_INTEG_FLAG) &&
530                    !(ret_flags & GSS_C_INTEG_FLAG)) {
531                 /*
532                  * here we wanted siging but didn't got it
533                  * from the gssapi library
534                  */
535                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
536                 goto failed;
537
538         } else if (ret_flags & GSS_C_CONF_FLAG) {
539                 /*
540                  * here we didn't want sealing
541                  * but the gssapi library forces it
542                  * so correct the needed wrap_type if
543                  * the caller didn't forced siging only
544                  */
545                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
546                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
547                         goto failed;
548                 }
549
550                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
551                 req_flags = ret_flags;
552
553         } else if (ret_flags & GSS_C_INTEG_FLAG) {
554                 /*
555                  * here we didn't want signing
556                  * but the gssapi library forces it
557                  * so correct the needed wrap_type if
558                  * the caller didn't forced plain
559                  */
560                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
561                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
562                         goto failed;
563                 }
564
565                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
566                 req_flags = ret_flags;
567         } else {
568                 /*
569                  * This could (should?) not happen
570                  */
571                 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
572                 goto failed;
573         
574         }
575
576         /* and wrap that in a shiny SPNEGO wrapper */
577         unwrapped = data_blob_const(output_token.value, output_token.length);
578         wrapped = spnego_gen_negTokenInit(talloc_tos(),
579                         spnego_mechs, &unwrapped, NULL);
580         gss_release_buffer(&minor_status, &output_token);
581         if (unwrapped.length > wrapped.length) {
582                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
583                 goto failed;
584         }
585
586         cred.bv_val = (char *)wrapped.data;
587         cred.bv_len = wrapped.length;
588
589         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, 
590                               &scred);
591         data_blob_free(&wrapped);
592         if (rc != LDAP_SUCCESS) {
593                 status = ADS_ERROR(rc);
594                 goto failed;
595         }
596
597         if (scred) {
598                 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
599         } else {
600                 wrapped = data_blob_null;
601         }
602
603         ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
604                                         OID_KERBEROS5_OLD,
605                                         &unwrapped);
606         if (scred) ber_bvfree(scred);
607         if (!ok) {
608                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
609                 goto failed;
610         }
611
612         input_token.value       = unwrapped.data;
613         input_token.length      = unwrapped.length;
614
615         /* 
616          * As we asked for mutal authentication
617          * we need to pass the servers response
618          * to gssapi
619          */
620         gss_rc = gss_init_sec_context(&minor_status,
621                                       gss_cred,
622                                       &context_handle,
623                                       serv_name,
624                                       mech_type,
625                                       req_flags,
626                                       0,
627                                       NULL,
628                                       &input_token,
629                                       &actual_mech_type,
630                                       &output_token,
631                                       &ret_flags,
632                                       NULL);
633         data_blob_free(&unwrapped);
634         if (gss_rc) {
635                 status = ADS_ERROR_GSS(gss_rc, minor_status);
636                 goto failed;
637         }
638
639         gss_release_buffer(&minor_status, &output_token);
640
641         /*
642          * If we the sign and seal options
643          * doesn't match after getting the response
644          * from the server, we don't want to use the connection
645          */
646         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
647         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
648
649         if (req_tmp != ret_tmp) {
650                 /* everythings fine... */
651                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
652                 goto failed;
653         }
654
655         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
656                 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
657
658                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
659                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
660                                              GSS_C_QOP_DEFAULT,
661                                              max_msg_size, &ads->ldap.out.max_unwrapped);
662                 if (gss_rc) {
663                         status = ADS_ERROR_GSS(gss_rc, minor_status);
664                         goto failed;
665                 }
666
667                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
668                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
669                 ads->ldap.in.max_wrapped = max_msg_size;
670                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
671                 if (!ADS_ERR_OK(status)) {
672                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
673                                 ads_errstr(status)));
674                         goto failed;
675                 }
676                 /* make sure we don't free context_handle */
677                 context_handle = GSS_C_NO_CONTEXT;
678         }
679
680         status = ADS_SUCCESS;
681
682 failed:
683         if (gss_cred != GSS_C_NO_CREDENTIAL)
684                 gss_release_cred(&minor_status, &gss_cred);
685         if (context_handle != GSS_C_NO_CONTEXT)
686                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
687         return status;
688 }
689
690 #endif /* HAVE_KRB5 */
691
692 #ifdef HAVE_KRB5
693 struct ads_service_principal {
694          char *string;
695 #ifdef HAVE_KRB5
696          gss_name_t name;
697 #endif
698 };
699
700 static void ads_free_service_principal(struct ads_service_principal *p)
701 {
702         SAFE_FREE(p->string);
703
704 #ifdef HAVE_KRB5
705         if (p->name) {
706                 uint32 minor_status;
707                 gss_release_name(&minor_status, &p->name);
708         }
709 #endif
710         ZERO_STRUCTP(p);
711 }
712
713
714 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
715                                               char **returned_principal)
716 {
717         char *princ = NULL;
718
719         if (ads->server.realm && ads->server.ldap_server) {
720                 char *server, *server_realm;
721
722                 server = SMB_STRDUP(ads->server.ldap_server);
723                 server_realm = SMB_STRDUP(ads->server.realm);
724
725                 if (!server || !server_realm) {
726                         SAFE_FREE(server);
727                         SAFE_FREE(server_realm);
728                         return ADS_ERROR(LDAP_NO_MEMORY);
729                 }
730
731                 if (!strlower_m(server)) {
732                         SAFE_FREE(server);
733                         SAFE_FREE(server_realm);
734                         return ADS_ERROR(LDAP_NO_MEMORY);
735                 }
736
737                 if (!strupper_m(server_realm)) {
738                         SAFE_FREE(server);
739                         SAFE_FREE(server_realm);
740                         return ADS_ERROR(LDAP_NO_MEMORY);
741                 }
742
743                 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
744                         SAFE_FREE(server);
745                         SAFE_FREE(server_realm);
746                         return ADS_ERROR(LDAP_NO_MEMORY);
747                 }
748
749                 SAFE_FREE(server);
750                 SAFE_FREE(server_realm);
751
752                 if (!princ) {
753                         return ADS_ERROR(LDAP_NO_MEMORY);
754                 }
755         } else if (ads->config.realm && ads->config.ldap_server_name) {
756                 char *server, *server_realm;
757
758                 server = SMB_STRDUP(ads->config.ldap_server_name);
759                 server_realm = SMB_STRDUP(ads->config.realm);
760
761                 if (!server || !server_realm) {
762                         SAFE_FREE(server);
763                         SAFE_FREE(server_realm);
764                         return ADS_ERROR(LDAP_NO_MEMORY);
765                 }
766
767                 if (!strlower_m(server)) {
768                         SAFE_FREE(server);
769                         SAFE_FREE(server_realm);
770                         return ADS_ERROR(LDAP_NO_MEMORY);
771                 }
772
773                 if (!strupper_m(server_realm)) {
774                         SAFE_FREE(server);
775                         SAFE_FREE(server_realm);
776                         return ADS_ERROR(LDAP_NO_MEMORY);
777                 }
778                 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
779                         SAFE_FREE(server);
780                         SAFE_FREE(server_realm);
781                         return ADS_ERROR(LDAP_NO_MEMORY);
782                 }
783
784                 SAFE_FREE(server);
785                 SAFE_FREE(server_realm);
786
787                 if (!princ) {
788                         return ADS_ERROR(LDAP_NO_MEMORY);
789                 }
790         }
791
792         if (!princ) {
793                 return ADS_ERROR(LDAP_PARAM_ERROR);
794         }
795
796         *returned_principal = princ;
797
798         return ADS_SUCCESS;
799 }
800
801 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
802                                                  const char *given_principal,
803                                                  struct ads_service_principal *p)
804 {
805         ADS_STATUS status;
806 #ifdef HAVE_KRB5
807         gss_buffer_desc input_name;
808         /* GSS_KRB5_NT_PRINCIPAL_NAME */
809         gss_OID_desc nt_principal =
810         {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
811         uint32 minor_status;
812         int gss_rc;
813 #endif
814
815         ZERO_STRUCTP(p);
816
817         /* I've seen a child Windows 2000 domain not send
818            the principal name back in the first round of
819            the SASL bind reply.  So we guess based on server
820            name and realm.  --jerry  */
821         /* Also try best guess when we get the w2k8 ignore principal
822            back, or when we are configured to ignore it - gd,
823            abartlet */
824
825         if (!lp_client_use_spnego_principal() ||
826             !given_principal ||
827             strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
828
829                 status = ads_guess_service_principal(ads, &p->string);
830                 if (!ADS_ERR_OK(status)) {
831                         return status;
832                 }
833         } else {
834                 p->string = SMB_STRDUP(given_principal);
835                 if (!p->string) {
836                         return ADS_ERROR(LDAP_NO_MEMORY);
837                 }
838         }
839
840 #ifdef HAVE_KRB5
841         input_name.value = p->string;
842         input_name.length = strlen(p->string);
843
844         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
845         if (gss_rc) {
846                 ads_free_service_principal(p);
847                 return ADS_ERROR_GSS(gss_rc, minor_status);
848         }
849 #endif
850
851         return ADS_SUCCESS;
852 }
853
854 /* 
855    perform a LDAP/SASL/SPNEGO/KRB5 bind
856 */
857 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
858 {
859         DATA_BLOB blob = data_blob_null;
860         struct berval cred, *scred = NULL;
861         DATA_BLOB session_key = data_blob_null;
862         int rc;
863
864         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
865                 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
866         }
867
868         rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
869                                      ads->auth.time_offset, &blob, &session_key, 0,
870                                      ads->auth.ccache_name,
871                                      &ads->auth.tgs_expire);
872
873         if (rc) {
874                 return ADS_ERROR_KRB5(rc);
875         }
876
877         /* now send the auth packet and we should be done */
878         cred.bv_val = (char *)blob.data;
879         cred.bv_len = blob.length;
880
881         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
882
883         data_blob_free(&blob);
884         data_blob_free(&session_key);
885         if(scred)
886                 ber_bvfree(scred);
887
888         return ADS_ERROR(rc);
889 }
890
891 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
892                                             struct ads_service_principal *p)
893 {
894 #ifdef HAVE_KRB5
895         /*
896          * we only use the gsskrb5 based implementation
897          * when sasl sign or seal is requested.
898          *
899          * This has the following reasons:
900          * - it's likely that the gssapi krb5 mech implementation
901          *   doesn't support to negotiate plain connections
902          * - the ads_sasl_spnego_rawkrb5_bind is more robust
903          *   against clock skew errors
904          */
905         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
906                 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
907         }
908 #endif
909         return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
910 }
911 #endif /* HAVE_KRB5 */
912
913 /* 
914    this performs a SASL/SPNEGO bind
915 */
916 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
917 {
918         struct berval *scred=NULL;
919         int rc, i;
920         ADS_STATUS status;
921         DATA_BLOB blob;
922         char *given_principal = NULL;
923         char *OIDs[ASN1_MAX_OIDS];
924 #ifdef HAVE_KRB5
925         bool got_kerberos_mechanism = False;
926 #endif
927
928         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
929
930         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
931                 status = ADS_ERROR(rc);
932                 goto failed;
933         }
934
935         blob = data_blob(scred->bv_val, scred->bv_len);
936
937         ber_bvfree(scred);
938
939 #if 0
940         file_save("sasl_spnego.dat", blob.data, blob.length);
941 #endif
942
943         /* the server sent us the first part of the SPNEGO exchange in the negprot 
944            reply */
945         if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
946                         OIDs[0] == NULL) {
947                 data_blob_free(&blob);
948                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
949                 goto failed;
950         }
951         data_blob_free(&blob);
952
953         /* make sure the server understands kerberos */
954         for (i=0;OIDs[i];i++) {
955                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
956 #ifdef HAVE_KRB5
957                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
958                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
959                         got_kerberos_mechanism = True;
960                 }
961 #endif
962                 talloc_free(OIDs[i]);
963         }
964         DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
965
966 #ifdef HAVE_KRB5
967         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
968             got_kerberos_mechanism) 
969         {
970                 struct ads_service_principal p;
971
972                 status = ads_generate_service_principal(ads, given_principal, &p);
973                 TALLOC_FREE(given_principal);
974                 if (!ADS_ERR_OK(status)) {
975                         return status;
976                 }
977
978                 status = ads_sasl_spnego_krb5_bind(ads, &p);
979                 if (ADS_ERR_OK(status)) {
980                         ads_free_service_principal(&p);
981                         return status;
982                 }
983
984                 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
985                           "calling kinit\n", ads_errstr(status)));
986
987                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
988
989                 if (ADS_ERR_OK(status)) {
990                         status = ads_sasl_spnego_krb5_bind(ads, &p);
991                         if (!ADS_ERR_OK(status)) {
992                                 DEBUG(0,("kinit succeeded but "
993                                         "ads_sasl_spnego_krb5_bind failed: %s\n",
994                                         ads_errstr(status)));
995                         }
996                 }
997
998                 ads_free_service_principal(&p);
999
1000                 /* only fallback to NTLMSSP if allowed */
1001                 if (ADS_ERR_OK(status) || 
1002                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
1003                         return status;
1004                 }
1005         } else
1006 #endif
1007         {
1008                 TALLOC_FREE(given_principal);
1009         }
1010
1011         /* lets do NTLMSSP ... this has the big advantage that we don't need
1012            to sync clocks, and we don't rely on special versions of the krb5 
1013            library for HMAC_MD4 encryption */
1014         return ads_sasl_spnego_ntlmssp_bind(ads);
1015
1016 failed:
1017         return status;
1018 }
1019
1020 #ifdef HAVE_KRB5
1021 #define MAX_GSS_PASSES 3
1022
1023 /* this performs a SASL/gssapi bind
1024    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
1025    is very dependent on correctly configured DNS whereas
1026    this routine is much less fragile
1027    see RFC2078 and RFC2222 for details
1028 */
1029 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
1030 {
1031         uint32 minor_status;
1032         gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
1033         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
1034         gss_OID mech_type = GSS_C_NULL_OID;
1035         gss_buffer_desc output_token, input_token;
1036         uint32 req_flags, ret_flags;
1037         int conf_state;
1038         struct berval cred;
1039         struct berval *scred = NULL;
1040         int i=0;
1041         int gss_rc, rc;
1042         uint8 *p;
1043         uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
1044         uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1045         ADS_STATUS status;
1046
1047         input_token.value = NULL;
1048         input_token.length = 0;
1049
1050         status = ads_init_gssapi_cred(ads, &gss_cred);
1051         if (!ADS_ERR_OK(status)) {
1052                 goto failed;
1053         }
1054
1055         /*
1056          * Note: here we always ask the gssapi for sign and seal
1057          *       as this is negotiated later after the mutal
1058          *       authentication
1059          */
1060         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
1061
1062         for (i=0; i < MAX_GSS_PASSES; i++) {
1063                 gss_rc = gss_init_sec_context(&minor_status,
1064                                           gss_cred,
1065                                           &context_handle,
1066                                           serv_name,
1067                                           mech_type,
1068                                           req_flags,
1069                                           0,
1070                                           NULL,
1071                                           &input_token,
1072                                           NULL,
1073                                           &output_token,
1074                                           &ret_flags,
1075                                           NULL);
1076                 if (scred) {
1077                         ber_bvfree(scred);
1078                         scred = NULL;
1079                 }
1080                 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
1081                         status = ADS_ERROR_GSS(gss_rc, minor_status);
1082                         goto failed;
1083                 }
1084
1085                 cred.bv_val = (char *)output_token.value;
1086                 cred.bv_len = output_token.length;
1087
1088                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
1089                                       &scred);
1090                 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
1091                         status = ADS_ERROR(rc);
1092                         goto failed;
1093                 }
1094
1095                 if (output_token.value) {
1096                         gss_release_buffer(&minor_status, &output_token);
1097                 }
1098
1099                 if (scred) {
1100                         input_token.value = scred->bv_val;
1101                         input_token.length = scred->bv_len;
1102                 } else {
1103                         input_token.value = NULL;
1104                         input_token.length = 0;
1105                 }
1106
1107                 if (gss_rc == 0) break;
1108         }
1109
1110         gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1111                             &conf_state,NULL);
1112         if (scred) {
1113                 ber_bvfree(scred);
1114                 scred = NULL;
1115         }
1116         if (gss_rc) {
1117                 status = ADS_ERROR_GSS(gss_rc, minor_status);
1118                 goto failed;
1119         }
1120
1121         p = (uint8 *)output_token.value;
1122
1123 #if 0
1124         file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1125 #endif
1126
1127         if (p) {
1128                 wrap_type = CVAL(p,0);
1129                 SCVAL(p,0,0);
1130                 max_msg_size = RIVAL(p,0);
1131         }
1132
1133         gss_release_buffer(&minor_status, &output_token);
1134
1135         if (!(wrap_type & ads->ldap.wrap_type)) {
1136                 /*
1137                  * the server doesn't supports the wrap
1138                  * type we want :-(
1139                  */
1140                 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1141                         ads->ldap.wrap_type, wrap_type));
1142                 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1143                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1144                 goto failed;
1145         }
1146
1147         /* 0x58 is the minimum windows accepts */
1148         if (max_msg_size < 0x58) {
1149                 max_msg_size = 0x58;
1150         }
1151
1152         output_token.length = 4;
1153         output_token.value = SMB_MALLOC(output_token.length);
1154         if (!output_token.value) {
1155                 output_token.length = 0;
1156                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1157                 goto failed;
1158         }
1159         p = (uint8 *)output_token.value;
1160
1161         RSIVAL(p,0,max_msg_size);
1162         SCVAL(p,0,ads->ldap.wrap_type);
1163
1164         /*
1165          * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1166          * but using ads->config.bind_path is the wrong! It should be
1167          * the DN of the user object!
1168          *
1169          * w2k3 gives an error when we send an incorrect DN, but sending nothing
1170          * is ok and matches the information flow used in GSS-SPNEGO.
1171          */
1172
1173         gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1174                         &output_token, /* used as *input* here. */
1175                         &conf_state,
1176                         &input_token); /* Used as *output* here. */
1177         if (gss_rc) {
1178                 status = ADS_ERROR_GSS(gss_rc, minor_status);
1179                 output_token.length = 0;
1180                 SAFE_FREE(output_token.value);
1181                 goto failed;
1182         }
1183
1184         /* We've finished with output_token. */
1185         SAFE_FREE(output_token.value);
1186         output_token.length = 0;
1187
1188         cred.bv_val = (char *)input_token.value;
1189         cred.bv_len = input_token.length;
1190
1191         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
1192                               &scred);
1193         gss_release_buffer(&minor_status, &input_token);
1194         status = ADS_ERROR(rc);
1195         if (!ADS_ERR_OK(status)) {
1196                 goto failed;
1197         }
1198
1199         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1200                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1201                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1202                                              GSS_C_QOP_DEFAULT,
1203                                              max_msg_size, &ads->ldap.out.max_unwrapped);
1204                 if (gss_rc) {
1205                         status = ADS_ERROR_GSS(gss_rc, minor_status);
1206                         goto failed;
1207                 }
1208
1209                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1210                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1211                 ads->ldap.in.max_wrapped = max_msg_size;
1212                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1213                 if (!ADS_ERR_OK(status)) {
1214                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1215                                 ads_errstr(status)));
1216                         goto failed;
1217                 }
1218                 /* make sure we don't free context_handle */
1219                 context_handle = GSS_C_NO_CONTEXT;
1220         }
1221
1222 failed:
1223         if (gss_cred != GSS_C_NO_CREDENTIAL)
1224                 gss_release_cred(&minor_status, &gss_cred);
1225         if (context_handle != GSS_C_NO_CONTEXT)
1226                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1227
1228         if(scred)
1229                 ber_bvfree(scred);
1230         return status;
1231 }
1232
1233 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1234 {
1235         ADS_STATUS status;
1236         struct ads_service_principal p;
1237
1238         status = ads_generate_service_principal(ads, NULL, &p);
1239         if (!ADS_ERR_OK(status)) {
1240                 return status;
1241         }
1242
1243         status = ads_sasl_gssapi_do_bind(ads, p.name);
1244         if (ADS_ERR_OK(status)) {
1245                 ads_free_service_principal(&p);
1246                 return status;
1247         }
1248
1249         DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1250                   "calling kinit\n", ads_errstr(status)));
1251
1252         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1253
1254         if (ADS_ERR_OK(status)) {
1255                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1256         }
1257
1258         ads_free_service_principal(&p);
1259
1260         return status;
1261 }
1262
1263 #endif /* HAVE_KRB5 */
1264
1265 /* mapping between SASL mechanisms and functions */
1266 static struct {
1267         const char *name;
1268         ADS_STATUS (*fn)(ADS_STRUCT *);
1269 } sasl_mechanisms[] = {
1270         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1271 #ifdef HAVE_KRB5
1272         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1273 #endif
1274         {NULL, NULL}
1275 };
1276
1277 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1278 {
1279         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1280         char **values;
1281         ADS_STATUS status;
1282         int i, j;
1283         LDAPMessage *res;
1284
1285         /* get a list of supported SASL mechanisms */
1286         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1287         if (!ADS_ERR_OK(status)) return status;
1288
1289         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1290
1291         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1292                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1293         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1294                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1295         } else {
1296                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1297         }
1298
1299         /* try our supported mechanisms in order */
1300         for (i=0;sasl_mechanisms[i].name;i++) {
1301                 /* see if the server supports it */
1302                 for (j=0;values && values[j];j++) {
1303                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1304                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1305 retry:
1306                                 status = sasl_mechanisms[i].fn(ads);
1307                                 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1308                                     status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1309                                     ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1310                                 {
1311                                         DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1312                                                  "retrying with signing enabled\n"));
1313                                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1314                                         goto retry;
1315                                 }
1316                                 ldap_value_free(values);
1317                                 ldap_msgfree(res);
1318                                 return status;
1319                         }
1320                 }
1321         }
1322
1323         ldap_value_free(values);
1324         ldap_msgfree(res);
1325         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1326 }
1327
1328 #endif /* HAVE_LDAP */
1329