Line data Source code
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 "auth/credentials/credentials.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/param.h"
28 : #include "lib/util/asn1.h"
29 :
30 54 : NTSTATUS ads_simple_creds(TALLOC_CTX *mem_ctx,
31 : const char *account_domain,
32 : const char *account_name,
33 : const char *password,
34 : struct cli_credentials **_creds)
35 : {
36 54 : TALLOC_CTX *frame = talloc_stackframe();
37 54 : struct cli_credentials *creds = NULL;
38 54 : struct loadparm_context *lp_ctx = NULL;
39 0 : bool ok;
40 :
41 54 : lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
42 54 : if (lp_ctx == NULL) {
43 0 : DBG_ERR("loadparm_init_s3 failed\n");
44 0 : TALLOC_FREE(frame);
45 0 : return NT_STATUS_INVALID_SERVER_STATE;
46 : }
47 :
48 54 : creds = cli_credentials_init(mem_ctx);
49 54 : if (creds == NULL) {
50 0 : TALLOC_FREE(frame);
51 0 : return NT_STATUS_NO_MEMORY;
52 : }
53 54 : talloc_steal(frame, creds);
54 :
55 54 : ok = cli_credentials_guess(creds, lp_ctx);
56 54 : if (!ok) {
57 0 : TALLOC_FREE(frame);
58 0 : return NT_STATUS_INTERNAL_ERROR;
59 : }
60 :
61 54 : if (account_domain != NULL && account_domain[0] != '\0') {
62 54 : ok = cli_credentials_set_domain(creds,
63 : account_domain,
64 : CRED_SPECIFIED);
65 54 : if (!ok) {
66 0 : TALLOC_FREE(frame);
67 0 : return NT_STATUS_NO_MEMORY;
68 : }
69 : }
70 54 : if (password != NULL) {
71 54 : ok = cli_credentials_set_password(creds,
72 : password,
73 : CRED_SPECIFIED);
74 54 : if (!ok) {
75 0 : TALLOC_FREE(frame);
76 0 : return NT_STATUS_NO_MEMORY;
77 : }
78 : }
79 :
80 54 : cli_credentials_parse_string(creds,
81 : account_name,
82 : CRED_SPECIFIED);
83 :
84 54 : *_creds = talloc_move(mem_ctx, &creds);
85 54 : TALLOC_FREE(frame);
86 54 : return NT_STATUS_OK;
87 : }
88 :
89 : #ifdef HAVE_LDAP
90 :
91 1602 : static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
92 : uint8_t *buf, uint32_t len)
93 : {
94 0 : struct gensec_security *gensec_security =
95 1602 : talloc_get_type_abort(wrap->wrap_private_data,
96 : struct gensec_security);
97 0 : NTSTATUS nt_status;
98 0 : DATA_BLOB unwrapped, wrapped;
99 1602 : TALLOC_CTX *frame = talloc_stackframe();
100 :
101 1602 : unwrapped = data_blob_const(buf, len);
102 :
103 1602 : nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
104 1602 : if (!NT_STATUS_IS_OK(nt_status)) {
105 0 : TALLOC_FREE(frame);
106 0 : return ADS_ERROR_NT(nt_status);
107 : }
108 :
109 1602 : if ((wrap->out.size - 4) < wrapped.length) {
110 0 : TALLOC_FREE(frame);
111 0 : return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
112 : }
113 :
114 : /* copy the wrapped blob to the right location */
115 1602 : memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
116 :
117 : /* set how many bytes must be written to the underlying socket */
118 1602 : wrap->out.left = 4 + wrapped.length;
119 :
120 1602 : TALLOC_FREE(frame);
121 :
122 1602 : return ADS_SUCCESS;
123 : }
124 :
125 1297 : static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
126 : {
127 0 : struct gensec_security *gensec_security =
128 1297 : talloc_get_type_abort(wrap->wrap_private_data,
129 : struct gensec_security);
130 0 : NTSTATUS nt_status;
131 0 : DATA_BLOB unwrapped, wrapped;
132 1297 : TALLOC_CTX *frame = talloc_stackframe();
133 :
134 1297 : wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
135 :
136 1297 : nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
137 1297 : if (!NT_STATUS_IS_OK(nt_status)) {
138 0 : TALLOC_FREE(frame);
139 0 : return ADS_ERROR_NT(nt_status);
140 : }
141 :
142 1297 : if (wrapped.length < unwrapped.length) {
143 0 : TALLOC_FREE(frame);
144 0 : return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
145 : }
146 :
147 : /* copy the wrapped blob to the right location */
148 1297 : memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
149 :
150 : /* set how many bytes must be written to the underlying socket */
151 1297 : wrap->in.left = unwrapped.length;
152 1297 : wrap->in.ofs = 4;
153 :
154 1297 : TALLOC_FREE(frame);
155 :
156 1297 : return ADS_SUCCESS;
157 : }
158 :
159 305 : static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
160 : {
161 0 : struct gensec_security *gensec_security =
162 305 : talloc_get_type_abort(wrap->wrap_private_data,
163 : struct gensec_security);
164 :
165 305 : TALLOC_FREE(gensec_security);
166 :
167 305 : wrap->wrap_ops = NULL;
168 305 : wrap->wrap_private_data = NULL;
169 305 : }
170 :
171 : static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
172 : .name = "gensec",
173 : .wrap = ads_sasl_gensec_wrap,
174 : .unwrap = ads_sasl_gensec_unwrap,
175 : .disconnect = ads_sasl_gensec_disconnect
176 : };
177 :
178 : /*
179 : perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
180 : we fit on one socket??)
181 : */
182 330 : static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
183 : struct cli_credentials *creds,
184 : const char *target_service,
185 : const char *target_hostname)
186 : {
187 330 : DATA_BLOB blob_in = data_blob_null;
188 330 : DATA_BLOB blob_out = data_blob_null;
189 0 : int rc;
190 0 : NTSTATUS nt_status;
191 0 : ADS_STATUS status;
192 0 : struct auth_generic_state *auth_generic_state;
193 330 : const char *sasl = "GSS-SPNEGO";
194 330 : const char *sasl_list[] = { sasl, NULL };
195 330 : struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
196 330 : const DATA_BLOB *tls_cb = NULL;
197 :
198 330 : nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
199 330 : if (!NT_STATUS_IS_OK(nt_status)) {
200 0 : return ADS_ERROR_NT(nt_status);
201 : }
202 :
203 330 : if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_creds(auth_generic_state, creds))) {
204 0 : return ADS_ERROR_NT(nt_status);
205 : }
206 :
207 330 : if (target_service != NULL) {
208 330 : nt_status = gensec_set_target_service(
209 330 : auth_generic_state->gensec_security,
210 : target_service);
211 330 : if (!NT_STATUS_IS_OK(nt_status)) {
212 0 : return ADS_ERROR_NT(nt_status);
213 : }
214 : }
215 :
216 330 : if (target_hostname != NULL) {
217 330 : nt_status = gensec_set_target_hostname(
218 330 : auth_generic_state->gensec_security,
219 : target_hostname);
220 330 : if (!NT_STATUS_IS_OK(nt_status)) {
221 0 : return ADS_ERROR_NT(nt_status);
222 : }
223 : }
224 :
225 330 : tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
226 330 : if (tls_cb != NULL) {
227 24 : uint32_t initiator_addrtype = 0;
228 24 : const DATA_BLOB *initiator_address = NULL;
229 24 : uint32_t acceptor_addrtype = 0;
230 24 : const DATA_BLOB *acceptor_address = NULL;
231 24 : const DATA_BLOB *application_data = tls_cb;
232 :
233 24 : nt_status = gensec_set_channel_bindings(auth_generic_state->gensec_security,
234 : initiator_addrtype,
235 : initiator_address,
236 : acceptor_addrtype,
237 : acceptor_address,
238 : application_data);
239 24 : if (!NT_STATUS_IS_OK(nt_status)) {
240 0 : DBG_WARNING("Failed to set GENSEC channel bindings: %s\n",
241 : nt_errstr(nt_status));
242 0 : return ADS_ERROR_NT(nt_status);
243 : }
244 : }
245 :
246 330 : switch (wrap->wrap_type) {
247 306 : case ADS_SASLWRAP_TYPE_SEAL:
248 306 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
249 306 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
250 306 : break;
251 0 : case ADS_SASLWRAP_TYPE_SIGN:
252 0 : if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
253 0 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
254 : } else {
255 : /*
256 : * windows servers are broken with sign only,
257 : * so we let the NTLMSSP backend to seal here,
258 : * via GENSEC_FEATURE_LDAP_STYLE.
259 : */
260 0 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
261 0 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
262 : }
263 0 : break;
264 24 : case ADS_SASLWRAP_TYPE_PLAIN:
265 24 : break;
266 : }
267 :
268 330 : nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
269 : sasl_list);
270 330 : if (!NT_STATUS_IS_OK(nt_status)) {
271 0 : return ADS_ERROR_NT(nt_status);
272 : }
273 :
274 330 : rc = LDAP_SASL_BIND_IN_PROGRESS;
275 330 : blob_in = data_blob_null;
276 330 : blob_out = data_blob_null;
277 :
278 334 : while (true) {
279 664 : struct berval cred, *scred = NULL;
280 :
281 664 : nt_status = gensec_update(auth_generic_state->gensec_security,
282 : talloc_tos(), blob_in, &blob_out);
283 664 : data_blob_free(&blob_in);
284 664 : if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
285 330 : && !NT_STATUS_IS_OK(nt_status))
286 : {
287 1 : TALLOC_FREE(auth_generic_state);
288 1 : data_blob_free(&blob_out);
289 1 : return ADS_ERROR_NT(nt_status);
290 : }
291 :
292 663 : if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
293 329 : break;
294 : }
295 :
296 334 : cred.bv_val = (char *)blob_out.data;
297 334 : cred.bv_len = blob_out.length;
298 334 : scred = NULL;
299 334 : rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
300 334 : data_blob_free(&blob_out);
301 334 : if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
302 0 : if (scred) {
303 0 : ber_bvfree(scred);
304 : }
305 :
306 0 : TALLOC_FREE(auth_generic_state);
307 0 : return ADS_ERROR(rc);
308 : }
309 334 : if (scred) {
310 334 : blob_in = data_blob_talloc(talloc_tos(),
311 : scred->bv_val,
312 : scred->bv_len);
313 334 : if (blob_in.length != scred->bv_len) {
314 0 : ber_bvfree(scred);
315 0 : TALLOC_FREE(auth_generic_state);
316 0 : return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
317 : }
318 334 : ber_bvfree(scred);
319 : } else {
320 0 : blob_in = data_blob_null;
321 : }
322 334 : if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
323 0 : break;
324 : }
325 : }
326 :
327 329 : data_blob_free(&blob_in);
328 329 : data_blob_free(&blob_out);
329 :
330 329 : if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
331 0 : bool ok;
332 :
333 305 : ok = gensec_have_feature(auth_generic_state->gensec_security,
334 : GENSEC_FEATURE_SEAL);
335 305 : if (!ok) {
336 0 : DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
337 0 : TALLOC_FREE(auth_generic_state);
338 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
339 : }
340 :
341 305 : ok = gensec_have_feature(auth_generic_state->gensec_security,
342 : GENSEC_FEATURE_SIGN);
343 305 : if (!ok) {
344 0 : DEBUG(0,("The gensec feature signing request, but unavailable\n"));
345 0 : TALLOC_FREE(auth_generic_state);
346 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
347 : }
348 :
349 24 : } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
350 0 : bool ok;
351 :
352 0 : ok = gensec_have_feature(auth_generic_state->gensec_security,
353 : GENSEC_FEATURE_SIGN);
354 0 : if (!ok) {
355 0 : DEBUG(0,("The gensec feature signing request, but unavailable\n"));
356 0 : TALLOC_FREE(auth_generic_state);
357 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
358 : }
359 : }
360 :
361 329 : ads->auth.expire_time = gensec_expire_time(auth_generic_state->gensec_security);
362 :
363 329 : if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
364 0 : size_t max_wrapped =
365 305 : gensec_max_wrapped_size(auth_generic_state->gensec_security);
366 305 : wrap->out.max_unwrapped =
367 305 : gensec_max_input_size(auth_generic_state->gensec_security);
368 :
369 305 : wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
370 : /*
371 : * Note that we have to truncate this to 0x2C
372 : * (taken from a capture with LDAP unbind), as the
373 : * signature size is not constant for Kerberos with
374 : * arcfour-hmac-md5.
375 : */
376 305 : wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
377 305 : wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
378 305 : status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
379 : &ads_sasl_gensec_ops,
380 305 : auth_generic_state->gensec_security);
381 305 : if (!ADS_ERR_OK(status)) {
382 0 : DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
383 : ads_errstr(status)));
384 0 : TALLOC_FREE(auth_generic_state);
385 0 : return status;
386 : }
387 : /* Only keep the gensec_security element around long-term */
388 305 : talloc_steal(NULL, auth_generic_state->gensec_security);
389 : }
390 329 : TALLOC_FREE(auth_generic_state);
391 :
392 329 : return ADS_ERROR(rc);
393 : }
394 :
395 : #ifdef HAVE_KRB5
396 : struct ads_service_principal {
397 : char *service;
398 : char *hostname;
399 : char *string;
400 : };
401 :
402 330 : static void ads_free_service_principal(struct ads_service_principal *p)
403 : {
404 330 : SAFE_FREE(p->service);
405 330 : SAFE_FREE(p->hostname);
406 330 : SAFE_FREE(p->string);
407 330 : ZERO_STRUCTP(p);
408 330 : }
409 :
410 330 : static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
411 : char **service,
412 : char **hostname,
413 : char **principal)
414 : {
415 330 : ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
416 330 : char *princ = NULL;
417 0 : TALLOC_CTX *frame;
418 330 : char *server = NULL;
419 330 : char *realm = NULL;
420 0 : int rc;
421 :
422 330 : frame = talloc_stackframe();
423 330 : if (frame == NULL) {
424 0 : return ADS_ERROR(LDAP_NO_MEMORY);
425 : }
426 :
427 330 : if (ads->server.realm && ads->server.ldap_server) {
428 148 : server = strlower_talloc(frame, ads->server.ldap_server);
429 148 : if (server == NULL) {
430 0 : goto out;
431 : }
432 :
433 148 : realm = strupper_talloc(frame, ads->server.realm);
434 148 : if (realm == NULL) {
435 0 : goto out;
436 : }
437 :
438 : /*
439 : * If we got a name which is bigger than a NetBIOS name,
440 : * but isn't a FQDN, create one.
441 : */
442 148 : if (strlen(server) > 15 && strstr(server, ".") == NULL) {
443 0 : char *dnsdomain;
444 :
445 0 : dnsdomain = strlower_talloc(frame, ads->server.realm);
446 0 : if (dnsdomain == NULL) {
447 0 : goto out;
448 : }
449 :
450 0 : server = talloc_asprintf(frame,
451 : "%s.%s",
452 : server, dnsdomain);
453 0 : if (server == NULL) {
454 0 : goto out;
455 : }
456 : }
457 182 : } else if (ads->config.realm && ads->config.ldap_server_name) {
458 182 : server = strlower_talloc(frame, ads->config.ldap_server_name);
459 182 : if (server == NULL) {
460 0 : goto out;
461 : }
462 :
463 182 : realm = strupper_talloc(frame, ads->config.realm);
464 182 : if (realm == NULL) {
465 0 : goto out;
466 : }
467 :
468 : /*
469 : * If we got a name which is bigger than a NetBIOS name,
470 : * but isn't a FQDN, create one.
471 : */
472 182 : if (strlen(server) > 15 && strstr(server, ".") == NULL) {
473 0 : char *dnsdomain;
474 :
475 0 : dnsdomain = strlower_talloc(frame, ads->server.realm);
476 0 : if (dnsdomain == NULL) {
477 0 : goto out;
478 : }
479 :
480 0 : server = talloc_asprintf(frame,
481 : "%s.%s",
482 : server, dnsdomain);
483 0 : if (server == NULL) {
484 0 : goto out;
485 : }
486 : }
487 : }
488 :
489 330 : if (server == NULL || realm == NULL) {
490 0 : goto out;
491 : }
492 :
493 330 : *service = SMB_STRDUP("ldap");
494 330 : if (*service == NULL) {
495 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
496 0 : goto out;
497 : }
498 330 : *hostname = SMB_STRDUP(server);
499 330 : if (*hostname == NULL) {
500 0 : SAFE_FREE(*service);
501 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
502 0 : goto out;
503 : }
504 330 : rc = asprintf(&princ, "ldap/%s@%s", server, realm);
505 330 : if (rc == -1 || princ == NULL) {
506 0 : SAFE_FREE(*service);
507 0 : SAFE_FREE(*hostname);
508 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
509 0 : goto out;
510 : }
511 :
512 330 : *principal = princ;
513 :
514 330 : status = ADS_SUCCESS;
515 330 : out:
516 330 : TALLOC_FREE(frame);
517 330 : return status;
518 : }
519 :
520 330 : static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
521 : struct ads_service_principal *p)
522 : {
523 0 : ADS_STATUS status;
524 :
525 330 : ZERO_STRUCTP(p);
526 :
527 330 : status = ads_guess_target(ads,
528 : &p->service,
529 : &p->hostname,
530 : &p->string);
531 330 : if (!ADS_ERR_OK(status)) {
532 0 : return status;
533 : }
534 :
535 330 : return ADS_SUCCESS;
536 : }
537 :
538 : #endif /* HAVE_KRB5 */
539 :
540 : /*
541 : this performs a SASL/SPNEGO bind
542 : */
543 330 : static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads,
544 : struct cli_credentials *creds)
545 : {
546 330 : TALLOC_CTX *frame = talloc_stackframe();
547 330 : struct ads_service_principal p = {0};
548 0 : ADS_STATUS status;
549 330 : const char *debug_username = NULL;
550 :
551 330 : status = ads_generate_service_principal(ads, &p);
552 330 : if (!ADS_ERR_OK(status)) {
553 0 : goto done;
554 : }
555 :
556 330 : debug_username = cli_credentials_get_unparsed_name(creds, frame);
557 330 : if (debug_username == NULL) {
558 0 : status = ADS_ERROR_SYSTEM(errno);
559 0 : goto done;
560 : }
561 :
562 330 : status = ads_sasl_spnego_gensec_bind(ads,
563 : creds,
564 330 : p.service,
565 330 : p.hostname);
566 330 : if (!ADS_ERR_OK(status)) {
567 1 : DBG_WARNING("ads_sasl_spnego_gensec_bind() failed "
568 : "for %s/%s with user[%s]: %s\n",
569 : p.service, p.hostname,
570 : debug_username,
571 : ads_errstr(status));
572 1 : goto done;
573 : }
574 :
575 329 : done:
576 330 : ads_free_service_principal(&p);
577 330 : TALLOC_FREE(frame);
578 330 : return status;
579 : }
580 :
581 330 : ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads, struct cli_credentials *creds)
582 : {
583 0 : ADS_STATUS status;
584 330 : struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
585 330 : bool tls = false;
586 :
587 330 : if (ads->auth.flags & ADS_AUTH_SASL_LDAPS) {
588 12 : tls = true;
589 12 : wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
590 318 : } else if (ads->auth.flags & ADS_AUTH_SASL_STARTTLS) {
591 12 : tls = true;
592 12 : wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
593 306 : } else if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
594 306 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
595 0 : } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
596 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
597 : } else {
598 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
599 : }
600 :
601 330 : if (tls) {
602 24 : const DATA_BLOB *tls_cb = NULL;
603 :
604 24 : tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
605 24 : if (tls_cb == NULL) {
606 0 : DBG_ERR("No TLS channel bindings available\n");
607 0 : return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
608 : }
609 : }
610 :
611 330 : retry:
612 330 : status = ads_sasl_spnego_bind(ads, creds);
613 330 : if (status.error_type == ENUM_ADS_ERROR_LDAP &&
614 329 : status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
615 0 : !tls &&
616 0 : wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
617 : {
618 0 : DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
619 : "retrying with signing enabled\n"));
620 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
621 0 : goto retry;
622 : }
623 330 : return status;
624 : }
625 :
626 : #endif /* HAVE_LDAP */
627 :
|