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