s3-ntlmssp Remove auth_ntlmssp_and_flags()
[metze/samba/wip.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                                          lp_netbios_name(),
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
152         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
153                 return ADS_ERROR_NT(nt_status);
154         }
155         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
156                 return ADS_ERROR_NT(nt_status);
157         }
158         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
159                 return ADS_ERROR_NT(nt_status);
160         }
161
162         switch (ads->ldap.wrap_type) {
163         case ADS_SASLWRAP_TYPE_SEAL:
164                 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
165                 break;
166         case ADS_SASLWRAP_TYPE_SIGN:
167                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
168                         features = NTLMSSP_FEATURE_SIGN;
169                 } else {
170                         /*
171                          * windows servers are broken with sign only,
172                          * so we need to use seal here too
173                          */
174                         features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
175                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
176                 }
177                 break;
178         case ADS_SASLWRAP_TYPE_PLAIN:
179                 break;
180         }
181
182         ntlmssp_want_feature(ntlmssp_state, features);
183
184         blob_in = data_blob_null;
185
186         do {
187                 nt_status = ntlmssp_update(ntlmssp_state, 
188                                            blob_in, &blob_out);
189                 data_blob_free(&blob_in);
190                 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 
191                      || NT_STATUS_IS_OK(nt_status))
192                     && blob_out.length) {
193                         if (turn == 1) {
194                                 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
195                                 /* and wrap it in a SPNEGO wrapper */
196                                 msg1 = spnego_gen_negTokenInit(talloc_tos(),
197                                                 OIDs_ntlm, &blob_out, NULL);
198                         } else {
199                                 /* wrap it in SPNEGO */
200                                 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
201                         }
202
203                         data_blob_free(&blob_out);
204
205                         cred.bv_val = (char *)msg1.data;
206                         cred.bv_len = msg1.length;
207                         scred = NULL;
208                         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
209                         data_blob_free(&msg1);
210                         if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
211                                 if (scred) {
212                                         ber_bvfree(scred);
213                                 }
214
215                                 TALLOC_FREE(ntlmssp_state);
216                                 return ADS_ERROR(rc);
217                         }
218                         if (scred) {
219                                 blob = data_blob(scred->bv_val, scred->bv_len);
220                                 ber_bvfree(scred);
221                         } else {
222                                 blob = data_blob_null;
223                         }
224
225                 } else {
226
227                         TALLOC_FREE(ntlmssp_state);
228                         data_blob_free(&blob_out);
229                         return ADS_ERROR_NT(nt_status);
230                 }
231                 
232                 if ((turn == 1) && 
233                     (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
234                         DATA_BLOB tmp_blob = data_blob_null;
235                         /* the server might give us back two challenges */
236                         if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in, 
237                                                     &tmp_blob)) {
238
239                                 TALLOC_FREE(ntlmssp_state);
240                                 data_blob_free(&blob);
241                                 DEBUG(3,("Failed to parse challenges\n"));
242                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
243                         }
244                         data_blob_free(&tmp_blob);
245                 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
246                         if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP, 
247                                                         &blob_in)) {
248
249                                 TALLOC_FREE(ntlmssp_state);
250                                 data_blob_free(&blob);
251                                 DEBUG(3,("Failed to parse auth response\n"));
252                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
253                         }
254                 }
255                 data_blob_free(&blob);
256                 data_blob_free(&blob_out);
257                 turn++;
258         } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
259         
260         /* we have a reference conter on ntlmssp_state, if we are signing
261            then the state will be kept by the signing engine */
262
263         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
264                 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
265                 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
266                 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
267                 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
268                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
269                 if (!ADS_ERR_OK(status)) {
270                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
271                                 ads_errstr(status)));
272                         TALLOC_FREE(ntlmssp_state);
273                         return status;
274                 }
275         } else {
276                 TALLOC_FREE(ntlmssp_state);
277         }
278
279         return ADS_ERROR(rc);
280 }
281
282 #ifdef HAVE_GSSAPI
283 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
284 {
285         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
286         ADS_STATUS status;
287         int gss_rc;
288         uint32 minor_status;
289         gss_buffer_desc unwrapped, wrapped;
290         int conf_req_flag, conf_state;
291
292         unwrapped.value         = buf;
293         unwrapped.length        = len;
294
295         /* for now request sign and seal */
296         conf_req_flag   = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
297
298         gss_rc = gss_wrap(&minor_status, context_handle,
299                           conf_req_flag, GSS_C_QOP_DEFAULT,
300                           &unwrapped, &conf_state,
301                           &wrapped);
302         status = ADS_ERROR_GSS(gss_rc, minor_status);
303         if (!ADS_ERR_OK(status)) return status;
304
305         if (conf_req_flag && conf_state == 0) {
306                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
307         }
308
309         if ((ads->ldap.out.size - 4) < wrapped.length) {
310                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
311         }
312
313         /* copy the wrapped blob to the right location */
314         memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
315
316         /* set how many bytes must be written to the underlying socket */
317         ads->ldap.out.left = 4 + wrapped.length;
318
319         gss_release_buffer(&minor_status, &wrapped);
320
321         return ADS_SUCCESS;
322 }
323
324 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
325 {
326         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
327         ADS_STATUS status;
328         int gss_rc;
329         uint32 minor_status;
330         gss_buffer_desc unwrapped, wrapped;
331         int conf_state;
332
333         wrapped.value   = ads->ldap.in.buf + 4;
334         wrapped.length  = ads->ldap.in.ofs - 4;
335
336         gss_rc = gss_unwrap(&minor_status, context_handle,
337                             &wrapped, &unwrapped,
338                             &conf_state, GSS_C_QOP_DEFAULT);
339         status = ADS_ERROR_GSS(gss_rc, minor_status);
340         if (!ADS_ERR_OK(status)) return status;
341
342         if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
343                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
344         }
345
346         if (wrapped.length < unwrapped.length) {
347                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
348         }
349
350         /* copy the wrapped blob to the right location */
351         memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
352
353         /* set how many bytes must be written to the underlying socket */
354         ads->ldap.in.left       = unwrapped.length;
355         ads->ldap.in.ofs        = 4;
356
357         gss_release_buffer(&minor_status, &unwrapped);
358
359         return ADS_SUCCESS;
360 }
361
362 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
363 {
364         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
365         uint32 minor_status;
366
367         gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
368
369         ads->ldap.wrap_ops = NULL;
370         ads->ldap.wrap_private_data = NULL;
371 }
372
373 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
374         .name           = "gssapi",
375         .wrap           = ads_sasl_gssapi_wrap,
376         .unwrap         = ads_sasl_gssapi_unwrap,
377         .disconnect     = ads_sasl_gssapi_disconnect
378 };
379
380 /* 
381    perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
382 */
383 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
384 {
385         ADS_STATUS status;
386         bool ok;
387         uint32 minor_status;
388         int gss_rc, rc;
389         gss_OID_desc krb5_mech_type =
390         {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
391         gss_OID mech_type = &krb5_mech_type;
392         gss_OID actual_mech_type = GSS_C_NULL_OID;
393         const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
394         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
395         gss_buffer_desc input_token, output_token;
396         uint32 req_flags, ret_flags;
397         uint32 req_tmp, ret_tmp;
398         DATA_BLOB unwrapped;
399         DATA_BLOB wrapped;
400         struct berval cred, *scred = NULL;
401
402         input_token.value = NULL;
403         input_token.length = 0;
404
405         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
406         switch (ads->ldap.wrap_type) {
407         case ADS_SASLWRAP_TYPE_SEAL:
408                 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
409                 break;
410         case ADS_SASLWRAP_TYPE_SIGN:
411                 req_flags |= GSS_C_INTEG_FLAG;
412                 break;
413         case ADS_SASLWRAP_TYPE_PLAIN:
414                 break;
415         }
416
417         /* Note: here we explicit ask for the krb5 mech_type */
418         gss_rc = gss_init_sec_context(&minor_status,
419                                       GSS_C_NO_CREDENTIAL,
420                                       &context_handle,
421                                       serv_name,
422                                       mech_type,
423                                       req_flags,
424                                       0,
425                                       NULL,
426                                       &input_token,
427                                       &actual_mech_type,
428                                       &output_token,
429                                       &ret_flags,
430                                       NULL);
431         if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
432                 status = ADS_ERROR_GSS(gss_rc, minor_status);
433                 goto failed;
434         }
435
436         /*
437          * As some gssapi krb5 mech implementations
438          * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
439          * to req_flags internaly, it's not possible to
440          * use plain or signing only connection via
441          * the gssapi interface.
442          *
443          * Because of this we need to check it the ret_flags
444          * has more flags as req_flags and correct the value
445          * of ads->ldap.wrap_type.
446          *
447          * I ads->auth.flags has ADS_AUTH_SASL_FORCE
448          * we need to give an error.
449          */
450         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
451         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
452
453         if (req_tmp == ret_tmp) {
454                 /* everythings fine... */
455
456         } else if (req_flags & GSS_C_CONF_FLAG) {
457                 /*
458                  * here we wanted sealing 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 ((req_flags & GSS_C_INTEG_FLAG) &&
465                    !(ret_flags & GSS_C_INTEG_FLAG)) {
466                 /*
467                  * here we wanted siging but didn't got it
468                  * from the gssapi library
469                  */
470                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
471                 goto failed;
472
473         } else if (ret_flags & GSS_C_CONF_FLAG) {
474                 /*
475                  * here we didn't want sealing
476                  * but the gssapi library forces it
477                  * so correct the needed wrap_type if
478                  * the caller didn't forced siging only
479                  */
480                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
481                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
482                         goto failed;
483                 }
484
485                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
486                 req_flags = ret_flags;
487
488         } else if (ret_flags & GSS_C_INTEG_FLAG) {
489                 /*
490                  * here we didn't want signing
491                  * but the gssapi library forces it
492                  * so correct the needed wrap_type if
493                  * the caller didn't forced plain
494                  */
495                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
496                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
497                         goto failed;
498                 }
499
500                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
501                 req_flags = ret_flags;
502         } else {
503                 /*
504                  * This could (should?) not happen
505                  */
506                 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
507                 goto failed;
508         
509         }
510
511         /* and wrap that in a shiny SPNEGO wrapper */
512         unwrapped = data_blob_const(output_token.value, output_token.length);
513         wrapped = spnego_gen_negTokenInit(talloc_tos(),
514                         spnego_mechs, &unwrapped, NULL);
515         gss_release_buffer(&minor_status, &output_token);
516         if (unwrapped.length > wrapped.length) {
517                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
518                 goto failed;
519         }
520
521         cred.bv_val = (char *)wrapped.data;
522         cred.bv_len = wrapped.length;
523
524         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, 
525                               &scred);
526         data_blob_free(&wrapped);
527         if (rc != LDAP_SUCCESS) {
528                 status = ADS_ERROR(rc);
529                 goto failed;
530         }
531
532         if (scred) {
533                 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
534         } else {
535                 wrapped = data_blob_null;
536         }
537
538         ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
539                                         OID_KERBEROS5_OLD,
540                                         &unwrapped);
541         if (scred) ber_bvfree(scred);
542         if (!ok) {
543                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
544                 goto failed;
545         }
546
547         input_token.value       = unwrapped.data;
548         input_token.length      = unwrapped.length;
549
550         /* 
551          * As we asked for mutal authentication
552          * we need to pass the servers response
553          * to gssapi
554          */
555         gss_rc = gss_init_sec_context(&minor_status,
556                                       GSS_C_NO_CREDENTIAL,
557                                       &context_handle,
558                                       serv_name,
559                                       mech_type,
560                                       req_flags,
561                                       0,
562                                       NULL,
563                                       &input_token,
564                                       &actual_mech_type,
565                                       &output_token,
566                                       &ret_flags,
567                                       NULL);
568         data_blob_free(&unwrapped);
569         if (gss_rc) {
570                 status = ADS_ERROR_GSS(gss_rc, minor_status);
571                 goto failed;
572         }
573
574         gss_release_buffer(&minor_status, &output_token);
575
576         /*
577          * If we the sign and seal options
578          * doesn't match after getting the response
579          * from the server, we don't want to use the connection
580          */
581         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
582         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
583
584         if (req_tmp != ret_tmp) {
585                 /* everythings fine... */
586                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
587                 goto failed;
588         }
589
590         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
591                 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
592
593                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
594                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
595                                              GSS_C_QOP_DEFAULT,
596                                              max_msg_size, &ads->ldap.out.max_unwrapped);
597                 if (gss_rc) {
598                         status = ADS_ERROR_GSS(gss_rc, minor_status);
599                         goto failed;
600                 }
601
602                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
603                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
604                 ads->ldap.in.max_wrapped = max_msg_size;
605                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
606                 if (!ADS_ERR_OK(status)) {
607                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
608                                 ads_errstr(status)));
609                         goto failed;
610                 }
611                 /* make sure we don't free context_handle */
612                 context_handle = GSS_C_NO_CONTEXT;
613         }
614
615         status = ADS_SUCCESS;
616
617 failed:
618         if (context_handle != GSS_C_NO_CONTEXT)
619                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
620         return status;
621 }
622
623 #endif /* HAVE_GSSAPI */
624
625 #ifdef HAVE_KRB5
626 struct ads_service_principal {
627          char *string;
628 #ifdef HAVE_GSSAPI
629          gss_name_t name;
630 #endif
631 };
632
633 static void ads_free_service_principal(struct ads_service_principal *p)
634 {
635         SAFE_FREE(p->string);
636
637 #ifdef HAVE_GSSAPI
638         if (p->name) {
639                 uint32 minor_status;
640                 gss_release_name(&minor_status, &p->name);
641         }
642 #endif
643         ZERO_STRUCTP(p);
644 }
645
646
647 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
648                                               char **returned_principal)
649 {
650         char *princ = NULL;
651
652         if (ads->server.realm && ads->server.ldap_server) {
653                 char *server, *server_realm;
654
655                 server = SMB_STRDUP(ads->server.ldap_server);
656                 server_realm = SMB_STRDUP(ads->server.realm);
657
658                 if (!server || !server_realm) {
659                         SAFE_FREE(server);
660                         SAFE_FREE(server_realm);
661                         return ADS_ERROR(LDAP_NO_MEMORY);
662                 }
663
664                 strlower_m(server);
665                 strupper_m(server_realm);
666                 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
667                         SAFE_FREE(server);
668                         SAFE_FREE(server_realm);
669                         return ADS_ERROR(LDAP_NO_MEMORY);
670                 }
671
672                 SAFE_FREE(server);
673                 SAFE_FREE(server_realm);
674
675                 if (!princ) {
676                         return ADS_ERROR(LDAP_NO_MEMORY);
677                 }
678         } else if (ads->config.realm && ads->config.ldap_server_name) {
679                 char *server, *server_realm;
680
681                 server = SMB_STRDUP(ads->config.ldap_server_name);
682                 server_realm = SMB_STRDUP(ads->config.realm);
683
684                 if (!server || !server_realm) {
685                         SAFE_FREE(server);
686                         SAFE_FREE(server_realm);
687                         return ADS_ERROR(LDAP_NO_MEMORY);
688                 }
689
690                 strlower_m(server);
691                 strupper_m(server_realm);
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_GSSAPI
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_GSSAPI
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_GSSAPI
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_GSSAPI
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_GSSAPI */
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_GSSAPI
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