2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2001
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.
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.
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/>.
24 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
26 struct ntlmssp_state *ntlmssp_state =
27 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
31 uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
33 /* copy the data to the right location */
34 memcpy(dptr, buf, len);
36 /* create the signature and may encrypt the data */
37 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
38 nt_status = ntlmssp_seal_packet(ntlmssp_state,
43 nt_status = ntlmssp_sign_packet(ntlmssp_state,
48 status = ADS_ERROR_NT(nt_status);
49 if (!ADS_ERR_OK(status)) return status;
51 /* copy the signature to the right location */
52 memcpy(ads->ldap.out.buf + 4,
53 sig.data, NTLMSSP_SIG_SIZE);
57 /* set how many bytes must be written to the underlying socket */
58 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
65 struct ntlmssp_state *ntlmssp_state =
66 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
70 uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
71 uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
73 /* wrap the signature into a DATA_BLOB */
74 sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
76 /* verify the signature and maybe decrypt the data */
77 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
78 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
83 nt_status = ntlmssp_check_packet(ntlmssp_state,
88 status = ADS_ERROR_NT(nt_status);
89 if (!ADS_ERR_OK(status)) return status;
91 /* set the amount of bytes for the upper layer and set the ofs to the data */
92 ads->ldap.in.left = dlen;
93 ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE;
98 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
100 struct ntlmssp_state *ntlmssp_state =
101 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
103 ntlmssp_end(&ntlmssp_state);
105 ads->ldap.wrap_ops = NULL;
106 ads->ldap.wrap_private_data = NULL;
109 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
111 .wrap = ads_sasl_ntlmssp_wrap,
112 .unwrap = ads_sasl_ntlmssp_unwrap,
113 .disconnect = ads_sasl_ntlmssp_disconnect
117 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
118 we fit on one socket??)
120 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
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;
132 struct ntlmssp_state *ntlmssp_state;
134 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
135 return ADS_ERROR_NT(nt_status);
137 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
139 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
140 return ADS_ERROR_NT(nt_status);
142 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
143 return ADS_ERROR_NT(nt_status);
145 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
146 return ADS_ERROR_NT(nt_status);
149 switch (ads->ldap.wrap_type) {
150 case ADS_SASLWRAP_TYPE_SEAL:
151 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
153 case ADS_SASLWRAP_TYPE_SIGN:
154 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
155 features = NTLMSSP_FEATURE_SIGN;
158 * windows servers are broken with sign only,
159 * so we need to use seal here too
161 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
162 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
165 case ADS_SASLWRAP_TYPE_PLAIN:
169 ntlmssp_want_feature(ntlmssp_state, features);
171 blob_in = data_blob_null;
174 nt_status = ntlmssp_update(ntlmssp_state,
176 data_blob_free(&blob_in);
177 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
178 || NT_STATUS_IS_OK(nt_status))
179 && blob_out.length) {
181 /* and wrap it in a SPNEGO wrapper */
182 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
184 /* wrap it in SPNEGO */
185 msg1 = spnego_gen_auth(blob_out);
188 data_blob_free(&blob_out);
190 cred.bv_val = (char *)msg1.data;
191 cred.bv_len = msg1.length;
193 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
194 data_blob_free(&msg1);
195 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
200 ntlmssp_end(&ntlmssp_state);
201 return ADS_ERROR(rc);
204 blob = data_blob(scred->bv_val, scred->bv_len);
207 blob = data_blob_null;
212 ntlmssp_end(&ntlmssp_state);
213 data_blob_free(&blob_out);
214 return ADS_ERROR_NT(nt_status);
218 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
219 DATA_BLOB tmp_blob = data_blob_null;
220 /* the server might give us back two challenges */
221 if (!spnego_parse_challenge(blob, &blob_in,
224 ntlmssp_end(&ntlmssp_state);
225 data_blob_free(&blob);
226 DEBUG(3,("Failed to parse challenges\n"));
227 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
229 data_blob_free(&tmp_blob);
230 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
231 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
234 ntlmssp_end(&ntlmssp_state);
235 data_blob_free(&blob);
236 DEBUG(3,("Failed to parse auth response\n"));
237 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
240 data_blob_free(&blob);
241 data_blob_free(&blob_out);
243 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
245 /* we have a reference conter on ntlmssp_state, if we are signing
246 then the state will be kept by the signing engine */
248 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
249 ads->ldap.out.min = 4;
250 ads->ldap.out.max = 0x0FFFFFFF - NTLMSSP_SIG_SIZE;
251 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
252 ads->ldap.in.min = 4;
253 ads->ldap.in.max = 0x0FFFFFFF;
254 ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
256 ntlmssp_end(&ntlmssp_state);
259 return ADS_ERROR(rc);
263 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
265 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
269 gss_buffer_desc unwrapped, wrapped;
270 int conf_req_flag, conf_state;
272 unwrapped.value = buf;
273 unwrapped.length = len;
275 /* for now request sign and seal */
276 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
278 gss_rc = gss_wrap(&minor_status, context_handle,
279 conf_req_flag, GSS_C_QOP_DEFAULT,
280 &unwrapped, &conf_state,
282 status = ADS_ERROR_GSS(gss_rc, minor_status);
283 if (!ADS_ERR_OK(status)) return status;
285 if (conf_req_flag && conf_state == 0) {
286 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
289 if ((ads->ldap.out.size - 4) < wrapped.length) {
290 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
293 /* copy the wrapped blob to the right location */
294 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
296 /* set how many bytes must be written to the underlying socket */
297 ads->ldap.out.left = 4 + wrapped.length;
299 gss_release_buffer(&minor_status, &wrapped);
304 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
306 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
310 gss_buffer_desc unwrapped, wrapped;
313 wrapped.value = ads->ldap.in.buf + 4;
314 wrapped.length = ads->ldap.in.ofs - 4;
316 gss_rc = gss_unwrap(&minor_status, context_handle,
317 &wrapped, &unwrapped,
318 &conf_state, GSS_C_QOP_DEFAULT);
319 status = ADS_ERROR_GSS(gss_rc, minor_status);
320 if (!ADS_ERR_OK(status)) return status;
322 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
323 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
326 if (wrapped.length < wrapped.length) {
327 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
330 /* copy the wrapped blob to the right location */
331 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
333 /* set how many bytes must be written to the underlying socket */
334 ads->ldap.in.left = unwrapped.length;
335 ads->ldap.in.ofs = 4;
337 gss_release_buffer(&minor_status, &unwrapped);
342 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
344 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
347 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
349 ads->ldap.wrap_ops = NULL;
350 ads->ldap.wrap_private_data = NULL;
353 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
355 .wrap = ads_sasl_gssapi_wrap,
356 .unwrap = ads_sasl_gssapi_unwrap,
357 .disconnect = ads_sasl_gssapi_disconnect
363 perform a LDAP/SASL/SPNEGO/KRB5 bind
365 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *principal)
367 DATA_BLOB blob = data_blob_null;
368 struct berval cred, *scred = NULL;
369 DATA_BLOB session_key = data_blob_null;
372 rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
373 &ads->auth.tgs_expire);
376 return ADS_ERROR_KRB5(rc);
379 /* now send the auth packet and we should be done */
380 cred.bv_val = (char *)blob.data;
381 cred.bv_len = blob.length;
383 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
385 data_blob_free(&blob);
386 data_blob_free(&session_key);
390 return ADS_ERROR(rc);
395 this performs a SASL/SPNEGO bind
397 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
399 struct berval *scred=NULL;
403 char *principal = NULL;
404 char *OIDs[ASN1_MAX_OIDS];
406 BOOL got_kerberos_mechanism = False;
409 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
411 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
412 status = ADS_ERROR(rc);
416 blob = data_blob(scred->bv_val, scred->bv_len);
421 file_save("sasl_spnego.dat", blob.data, blob.length);
424 /* the server sent us the first part of the SPNEGO exchange in the negprot
426 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
427 data_blob_free(&blob);
428 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
431 data_blob_free(&blob);
433 /* make sure the server understands kerberos */
434 for (i=0;OIDs[i];i++) {
435 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
437 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
438 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
439 got_kerberos_mechanism = True;
444 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", principal));
447 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
448 got_kerberos_mechanism)
450 /* I've seen a child Windows 2000 domain not send
451 the principal name back in the first round of
452 the SASL bind reply. So we guess based on server
453 name and realm. --jerry */
455 if ( ads->server.realm && ads->server.ldap_server ) {
456 char *server, *server_realm;
458 server = SMB_STRDUP( ads->server.ldap_server );
459 server_realm = SMB_STRDUP( ads->server.realm );
461 if ( !server || !server_realm )
462 return ADS_ERROR(LDAP_NO_MEMORY);
464 strlower_m( server );
465 strupper_m( server_realm );
466 asprintf( &principal, "ldap/%s@%s", server, server_realm );
469 SAFE_FREE( server_realm );
472 return ADS_ERROR(LDAP_NO_MEMORY);
477 status = ads_sasl_spnego_krb5_bind(ads, principal);
478 if (ADS_ERR_OK(status)) {
479 SAFE_FREE(principal);
483 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
484 "calling kinit\n", ads_errstr(status)));
486 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
488 if (ADS_ERR_OK(status)) {
489 status = ads_sasl_spnego_krb5_bind(ads, principal);
492 /* only fallback to NTLMSSP if allowed */
493 if (ADS_ERR_OK(status) ||
494 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
495 SAFE_FREE(principal);
501 SAFE_FREE(principal);
503 /* lets do NTLMSSP ... this has the big advantage that we don't need
504 to sync clocks, and we don't rely on special versions of the krb5
505 library for HMAC_MD4 encryption */
506 return ads_sasl_spnego_ntlmssp_bind(ads);
513 #define MAX_GSS_PASSES 3
515 /* this performs a SASL/gssapi bind
516 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
517 is very dependent on correctly configured DNS whereas
518 this routine is much less fragile
519 see RFC2078 and RFC2222 for details
521 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
524 gss_name_t serv_name;
525 gss_buffer_desc input_name;
526 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
527 gss_OID mech_type = GSS_C_NULL_OID;
528 gss_buffer_desc output_token, input_token;
529 uint32 req_flags, ret_flags;
532 struct berval *scred = NULL;
536 uint32 max_msg_size = 0;
539 krb5_principal principal = NULL;
540 krb5_context ctx = NULL;
541 krb5_enctype enc_types[] = {
542 #ifdef ENCTYPE_ARCFOUR_HMAC
543 ENCTYPE_ARCFOUR_HMAC,
547 gss_OID_desc nt_principal =
548 {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
550 /* we need to fetch a service ticket as the ldap user in the
551 servers realm, regardless of our realm */
552 asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);
554 initialize_krb5_error_table();
555 status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
556 if (!ADS_ERR_OK(status)) {
560 status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
561 if (!ADS_ERR_OK(status)) {
563 krb5_free_context(ctx);
566 status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
567 if (!ADS_ERR_OK(status)) {
569 krb5_free_context(ctx);
573 input_name.value = &principal;
574 input_name.length = sizeof(principal);
576 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);
579 * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
580 * to point to the *address* of the krb5_principal, and the gss libraries
581 * to a shallow copy of the krb5_principal pointer - so we need to keep
582 * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
583 * Just one more way in which MIT engineers screwed me over.... JRA.
589 krb5_free_principal(ctx, principal);
590 krb5_free_context(ctx);
591 return ADS_ERROR_GSS(gss_rc, minor_status);
594 input_token.value = NULL;
595 input_token.length = 0;
597 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
598 switch (ads->ldap.wrap_type) {
599 case ADS_SASLWRAP_TYPE_SEAL:
600 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
602 case ADS_SASLWRAP_TYPE_SIGN:
603 req_flags |= GSS_C_INTEG_FLAG;
605 case ADS_SASLWRAP_TYPE_PLAIN:
609 for (i=0; i < MAX_GSS_PASSES; i++) {
610 gss_rc = gss_init_sec_context(&minor_status,
624 if (input_token.value) {
625 gss_release_buffer(&minor_status, &input_token);
628 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
629 status = ADS_ERROR_GSS(gss_rc, minor_status);
633 cred.bv_val = (char *)output_token.value;
634 cred.bv_len = output_token.length;
636 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
638 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
639 status = ADS_ERROR(rc);
643 if (output_token.value) {
644 gss_release_buffer(&minor_status, &output_token);
648 input_token.value = scred->bv_val;
649 input_token.length = scred->bv_len;
651 input_token.value = NULL;
652 input_token.length = 0;
655 if (gss_rc == 0) break;
658 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
661 status = ADS_ERROR_GSS(gss_rc, minor_status);
665 gss_release_buffer(&minor_status, &input_token);
667 p = (uint8 *)output_token.value;
670 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
674 max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
677 gss_release_buffer(&minor_status, &output_token);
679 output_token.length = 4;
680 output_token.value = SMB_MALLOC(output_token.length);
681 p = (uint8 *)output_token.value;
683 *p++ = ads->ldap.wrap_type;
684 /* choose the same size as the server gave us */
685 *p++ = max_msg_size>>16;
686 *p++ = max_msg_size>>8;
689 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
690 * but using ads->config.bind_path is the wrong! It should be
691 * the DN of the user object!
693 * w2k3 gives an error when we send an incorrect DN, but sending nothing
694 * is ok and matches the information flow used in GSS-SPNEGO.
697 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
698 &output_token, &conf_state,
701 status = ADS_ERROR_GSS(gss_rc, minor_status);
705 free(output_token.value);
707 cred.bv_val = (char *)input_token.value;
708 cred.bv_len = input_token.length;
710 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
712 gss_release_buffer(&minor_status, &input_token);
713 status = ADS_ERROR(rc);
714 if (!ADS_ERR_OK(status)) {
718 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
719 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
720 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
722 max_msg_size, &ads->ldap.out.max);
724 status = ADS_ERROR_GSS(gss_rc, minor_status);
728 ads->ldap.out.min = 4;
729 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max;
730 ads->ldap.in.min = 4;
731 ads->ldap.in.max = max_msg_size;
732 ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
733 /* make sure we don't free context_handle */
734 context_handle = GSS_C_NO_CONTEXT;
738 gss_release_name(&minor_status, &serv_name);
739 if (context_handle != GSS_C_NO_CONTEXT)
740 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
741 krb5_free_principal(ctx, principal);
742 krb5_free_context(ctx);
748 #endif /* HAVE_GGSAPI */
750 /* mapping between SASL mechanisms and functions */
753 ADS_STATUS (*fn)(ADS_STRUCT *);
754 } sasl_mechanisms[] = {
755 {"GSS-SPNEGO", ads_sasl_spnego_bind},
757 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
762 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
764 const char *attrs[] = {"supportedSASLMechanisms", NULL};
770 /* get a list of supported SASL mechanisms */
771 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
772 if (!ADS_ERR_OK(status)) return status;
774 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
776 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
777 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
778 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
779 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
781 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
784 /* try our supported mechanisms in order */
785 for (i=0;sasl_mechanisms[i].name;i++) {
786 /* see if the server supports it */
787 for (j=0;values && values[j];j++) {
788 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
789 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
790 status = sasl_mechanisms[i].fn(ads);
791 ldap_value_free(values);
798 ldap_value_free(values);
800 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
803 #endif /* HAVE_LDAP */