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