smbXsrv_session: Remove a "can't happen" NULL check
[Samba.git] / source3 / libads / sasl.c
blob5ae8b999e66914e4e88fb5f43001d78f77b585ff
1 /*
2 Unix SMB/CIFS implementation.
3 ads sasl code
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/>.
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "auth/credentials/credentials.h"
23 #include "auth/gensec/gensec.h"
24 #include "auth_generic.h"
25 #include "ads.h"
26 #include "smb_krb5.h"
27 #include "system/gssapi.h"
28 #include "lib/param/loadparm.h"
29 #include "krb5_env.h"
30 #include "lib/util/asn1.h"
32 #ifdef HAVE_LDAP
34 static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
35 uint8_t *buf, uint32_t len)
37 struct gensec_security *gensec_security =
38 talloc_get_type_abort(wrap->wrap_private_data,
39 struct gensec_security);
40 NTSTATUS nt_status;
41 DATA_BLOB unwrapped, wrapped;
42 TALLOC_CTX *frame = talloc_stackframe();
44 unwrapped = data_blob_const(buf, len);
46 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
47 if (!NT_STATUS_IS_OK(nt_status)) {
48 TALLOC_FREE(frame);
49 return ADS_ERROR_NT(nt_status);
52 if ((wrap->out.size - 4) < wrapped.length) {
53 TALLOC_FREE(frame);
54 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
57 /* copy the wrapped blob to the right location */
58 memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
60 /* set how many bytes must be written to the underlying socket */
61 wrap->out.left = 4 + wrapped.length;
63 TALLOC_FREE(frame);
65 return ADS_SUCCESS;
68 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
70 struct gensec_security *gensec_security =
71 talloc_get_type_abort(wrap->wrap_private_data,
72 struct gensec_security);
73 NTSTATUS nt_status;
74 DATA_BLOB unwrapped, wrapped;
75 TALLOC_CTX *frame = talloc_stackframe();
77 wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
79 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
80 if (!NT_STATUS_IS_OK(nt_status)) {
81 TALLOC_FREE(frame);
82 return ADS_ERROR_NT(nt_status);
85 if (wrapped.length < unwrapped.length) {
86 TALLOC_FREE(frame);
87 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
90 /* copy the wrapped blob to the right location */
91 memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
93 /* set how many bytes must be written to the underlying socket */
94 wrap->in.left = unwrapped.length;
95 wrap->in.ofs = 4;
97 TALLOC_FREE(frame);
99 return ADS_SUCCESS;
102 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
104 struct gensec_security *gensec_security =
105 talloc_get_type_abort(wrap->wrap_private_data,
106 struct gensec_security);
108 TALLOC_FREE(gensec_security);
110 wrap->wrap_ops = NULL;
111 wrap->wrap_private_data = NULL;
114 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
115 .name = "gensec",
116 .wrap = ads_sasl_gensec_wrap,
117 .unwrap = ads_sasl_gensec_unwrap,
118 .disconnect = ads_sasl_gensec_disconnect
122 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
123 we fit on one socket??)
125 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
126 const char *sasl,
127 enum credentials_use_kerberos krb5_state,
128 const char *target_service,
129 const char *target_hostname,
130 const DATA_BLOB server_blob)
132 DATA_BLOB blob_in = data_blob_null;
133 DATA_BLOB blob_out = data_blob_null;
134 int rc;
135 NTSTATUS nt_status;
136 ADS_STATUS status;
137 struct auth_generic_state *auth_generic_state;
138 bool use_spnego_principal = lp_client_use_spnego_principal();
139 const char *sasl_list[] = { sasl, NULL };
140 NTTIME end_nt_time;
141 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
143 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
144 if (!NT_STATUS_IS_OK(nt_status)) {
145 return ADS_ERROR_NT(nt_status);
148 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
149 return ADS_ERROR_NT(nt_status);
151 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
152 return ADS_ERROR_NT(nt_status);
154 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
155 return ADS_ERROR_NT(nt_status);
158 if (server_blob.length == 0) {
159 use_spnego_principal = false;
162 if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
163 use_spnego_principal = false;
166 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
167 krb5_state,
168 CRED_SPECIFIED);
170 if (target_service != NULL) {
171 nt_status = gensec_set_target_service(
172 auth_generic_state->gensec_security,
173 target_service);
174 if (!NT_STATUS_IS_OK(nt_status)) {
175 return ADS_ERROR_NT(nt_status);
179 if (target_hostname != NULL) {
180 nt_status = gensec_set_target_hostname(
181 auth_generic_state->gensec_security,
182 target_hostname);
183 if (!NT_STATUS_IS_OK(nt_status)) {
184 return ADS_ERROR_NT(nt_status);
188 if (target_service != NULL && target_hostname != NULL) {
189 use_spnego_principal = false;
192 switch (wrap->wrap_type) {
193 case ADS_SASLWRAP_TYPE_SEAL:
194 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
195 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
196 break;
197 case ADS_SASLWRAP_TYPE_SIGN:
198 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
199 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
200 } else {
202 * windows servers are broken with sign only,
203 * so we let the NTLMSSP backend to seal here,
204 * via GENSEC_FEATURE_LDAP_STYLE.
206 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
207 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
209 break;
210 case ADS_SASLWRAP_TYPE_PLAIN:
211 break;
214 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
215 sasl_list);
216 if (!NT_STATUS_IS_OK(nt_status)) {
217 return ADS_ERROR_NT(nt_status);
220 rc = LDAP_SASL_BIND_IN_PROGRESS;
221 if (use_spnego_principal) {
222 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
223 if (blob_in.length == 0) {
224 TALLOC_FREE(auth_generic_state);
225 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
227 } else {
228 blob_in = data_blob_null;
230 blob_out = data_blob_null;
232 while (true) {
233 struct berval cred, *scred = NULL;
235 nt_status = gensec_update(auth_generic_state->gensec_security,
236 talloc_tos(), blob_in, &blob_out);
237 data_blob_free(&blob_in);
238 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
239 && !NT_STATUS_IS_OK(nt_status))
241 TALLOC_FREE(auth_generic_state);
242 data_blob_free(&blob_out);
243 return ADS_ERROR_NT(nt_status);
246 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
247 break;
250 cred.bv_val = (char *)blob_out.data;
251 cred.bv_len = blob_out.length;
252 scred = NULL;
253 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
254 data_blob_free(&blob_out);
255 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
256 if (scred) {
257 ber_bvfree(scred);
260 TALLOC_FREE(auth_generic_state);
261 return ADS_ERROR(rc);
263 if (scred) {
264 blob_in = data_blob_talloc(talloc_tos(),
265 scred->bv_val,
266 scred->bv_len);
267 if (blob_in.length != scred->bv_len) {
268 ber_bvfree(scred);
269 TALLOC_FREE(auth_generic_state);
270 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
272 ber_bvfree(scred);
273 } else {
274 blob_in = data_blob_null;
276 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
277 break;
281 data_blob_free(&blob_in);
282 data_blob_free(&blob_out);
284 if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
285 bool ok;
287 ok = gensec_have_feature(auth_generic_state->gensec_security,
288 GENSEC_FEATURE_SEAL);
289 if (!ok) {
290 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
291 TALLOC_FREE(auth_generic_state);
292 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
295 ok = gensec_have_feature(auth_generic_state->gensec_security,
296 GENSEC_FEATURE_SIGN);
297 if (!ok) {
298 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
299 TALLOC_FREE(auth_generic_state);
300 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
303 } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
304 bool ok;
306 ok = gensec_have_feature(auth_generic_state->gensec_security,
307 GENSEC_FEATURE_SIGN);
308 if (!ok) {
309 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
310 TALLOC_FREE(auth_generic_state);
311 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
315 ads->auth.tgs_expire = LONG_MAX;
316 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
317 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
318 struct timeval tv;
319 nttime_to_timeval(&tv, end_nt_time);
320 ads->auth.tgs_expire = tv.tv_sec;
323 if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
324 size_t max_wrapped =
325 gensec_max_wrapped_size(auth_generic_state->gensec_security);
326 wrap->out.max_unwrapped =
327 gensec_max_input_size(auth_generic_state->gensec_security);
329 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
331 * Note that we have to truncate this to 0x2C
332 * (taken from a capture with LDAP unbind), as the
333 * signature size is not constant for Kerberos with
334 * arcfour-hmac-md5.
336 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
337 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
338 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
339 &ads_sasl_gensec_ops,
340 auth_generic_state->gensec_security);
341 if (!ADS_ERR_OK(status)) {
342 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
343 ads_errstr(status)));
344 TALLOC_FREE(auth_generic_state);
345 return status;
347 /* Only keep the gensec_security element around long-term */
348 talloc_steal(NULL, auth_generic_state->gensec_security);
350 TALLOC_FREE(auth_generic_state);
352 return ADS_ERROR(rc);
355 #ifdef HAVE_KRB5
356 struct ads_service_principal {
357 char *service;
358 char *hostname;
359 char *string;
362 static void ads_free_service_principal(struct ads_service_principal *p)
364 SAFE_FREE(p->service);
365 SAFE_FREE(p->hostname);
366 SAFE_FREE(p->string);
367 ZERO_STRUCTP(p);
370 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
371 char **service,
372 char **hostname,
373 char **principal)
375 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
376 char *princ = NULL;
377 TALLOC_CTX *frame;
378 char *server = NULL;
379 char *realm = NULL;
380 int rc;
382 frame = talloc_stackframe();
383 if (frame == NULL) {
384 return ADS_ERROR(LDAP_NO_MEMORY);
387 if (ads->server.realm && ads->server.ldap_server) {
388 server = strlower_talloc(frame, ads->server.ldap_server);
389 if (server == NULL) {
390 goto out;
393 realm = strupper_talloc(frame, ads->server.realm);
394 if (realm == NULL) {
395 goto out;
399 * If we got a name which is bigger than a NetBIOS name,
400 * but isn't a FQDN, create one.
402 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
403 char *dnsdomain;
405 dnsdomain = strlower_talloc(frame, ads->server.realm);
406 if (dnsdomain == NULL) {
407 goto out;
410 server = talloc_asprintf(frame,
411 "%s.%s",
412 server, dnsdomain);
413 if (server == NULL) {
414 goto out;
417 } else if (ads->config.realm && ads->config.ldap_server_name) {
418 server = strlower_talloc(frame, ads->config.ldap_server_name);
419 if (server == NULL) {
420 goto out;
423 realm = strupper_talloc(frame, ads->config.realm);
424 if (realm == NULL) {
425 goto out;
429 * If we got a name which is bigger than a NetBIOS name,
430 * but isn't a FQDN, create one.
432 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
433 char *dnsdomain;
435 dnsdomain = strlower_talloc(frame, ads->server.realm);
436 if (dnsdomain == NULL) {
437 goto out;
440 server = talloc_asprintf(frame,
441 "%s.%s",
442 server, dnsdomain);
443 if (server == NULL) {
444 goto out;
449 if (server == NULL || realm == NULL) {
450 goto out;
453 *service = SMB_STRDUP("ldap");
454 if (*service == NULL) {
455 status = ADS_ERROR(LDAP_PARAM_ERROR);
456 goto out;
458 *hostname = SMB_STRDUP(server);
459 if (*hostname == NULL) {
460 SAFE_FREE(*service);
461 status = ADS_ERROR(LDAP_PARAM_ERROR);
462 goto out;
464 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
465 if (rc == -1 || princ == NULL) {
466 SAFE_FREE(*service);
467 SAFE_FREE(*hostname);
468 status = ADS_ERROR(LDAP_PARAM_ERROR);
469 goto out;
472 *principal = princ;
474 status = ADS_SUCCESS;
475 out:
476 TALLOC_FREE(frame);
477 return status;
480 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
481 struct ads_service_principal *p)
483 ADS_STATUS status;
485 ZERO_STRUCTP(p);
487 status = ads_guess_target(ads,
488 &p->service,
489 &p->hostname,
490 &p->string);
491 if (!ADS_ERR_OK(status)) {
492 return status;
495 return ADS_SUCCESS;
498 #endif /* HAVE_KRB5 */
501 parse a negTokenInit packet giving a GUID, a list of supported
502 OIDs (the mechanisms) and a principal name string
504 static bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
505 DATA_BLOB blob,
506 char *OIDs[ASN1_MAX_OIDS],
507 char **principal,
508 DATA_BLOB *secblob)
510 int i;
511 bool ret = false;
512 ASN1_DATA *data;
514 for (i = 0; i < ASN1_MAX_OIDS; i++) {
515 OIDs[i] = NULL;
518 if (principal) {
519 *principal = NULL;
521 if (secblob) {
522 *secblob = data_blob_null;
525 data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
526 if (data == NULL) {
527 return false;
530 if (!asn1_load(data, blob)) goto err;
532 if (!asn1_start_tag(data,ASN1_APPLICATION(0))) goto err;
534 if (!asn1_check_OID(data,OID_SPNEGO)) goto err;
536 /* negTokenInit [0] NegTokenInit */
537 if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
538 if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
540 /* mechTypes [0] MechTypeList OPTIONAL */
542 /* Not really optional, we depend on this to decide
543 * what mechanisms we have to work with. */
545 if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
546 if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
547 for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
548 if (!asn1_read_OID(data,ctx, &OIDs[i])) {
549 goto err;
551 if (asn1_has_error(data)) {
552 goto err;
555 OIDs[i] = NULL;
556 if (!asn1_end_tag(data)) goto err;
557 if (!asn1_end_tag(data)) goto err;
560 Win7 + Live Sign-in Assistant attaches a mechToken
561 ASN1_CONTEXT(2) to the negTokenInit packet
562 which breaks our negotiation if we just assume
563 the next tag is ASN1_CONTEXT(3).
566 if (asn1_peek_tag(data, ASN1_CONTEXT(1))) {
567 uint8_t flags;
569 /* reqFlags [1] ContextFlags OPTIONAL */
570 if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err;
571 if (!asn1_start_tag(data, ASN1_BIT_STRING)) goto err;
572 while (asn1_tag_remaining(data) > 0) {
573 if (!asn1_read_uint8(data, &flags)) goto err;
575 if (!asn1_end_tag(data)) goto err;
576 if (!asn1_end_tag(data)) goto err;
579 if (asn1_peek_tag(data, ASN1_CONTEXT(2))) {
580 DATA_BLOB sblob = data_blob_null;
581 /* mechToken [2] OCTET STRING OPTIONAL */
582 if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err;
583 if (!asn1_read_OctetString(data, ctx, &sblob)) goto err;
584 if (!asn1_end_tag(data)) {
585 data_blob_free(&sblob);
586 goto err;
588 if (secblob) {
589 *secblob = sblob;
590 } else {
591 data_blob_free(&sblob);
595 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
596 char *princ = NULL;
597 /* mechListMIC [3] OCTET STRING OPTIONAL */
598 if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err;
599 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err;
600 if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err;
601 if (!asn1_read_GeneralString(data, ctx, &princ)) goto err;
602 if (!asn1_end_tag(data)) goto err;
603 if (!asn1_end_tag(data)) goto err;
604 if (!asn1_end_tag(data)) goto err;
605 if (principal) {
606 *principal = princ;
607 } else {
608 TALLOC_FREE(princ);
612 if (!asn1_end_tag(data)) goto err;
613 if (!asn1_end_tag(data)) goto err;
615 if (!asn1_end_tag(data)) goto err;
617 ret = !asn1_has_error(data);
619 err:
621 if (asn1_has_error(data)) {
622 int j;
623 if (principal) {
624 TALLOC_FREE(*principal);
626 if (secblob) {
627 data_blob_free(secblob);
629 for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
630 TALLOC_FREE(OIDs[j]);
634 asn1_free(data);
635 return ret;
639 this performs a SASL/SPNEGO bind
641 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
643 TALLOC_CTX *frame = talloc_stackframe();
644 struct ads_service_principal p = {0};
645 struct berval *scred=NULL;
646 int rc, i;
647 ADS_STATUS status;
648 DATA_BLOB blob = data_blob_null;
649 char *given_principal = NULL;
650 char *OIDs[ASN1_MAX_OIDS];
651 #ifdef HAVE_KRB5
652 bool got_kerberos_mechanism = False;
653 #endif
654 const char *mech = NULL;
656 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
658 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
659 status = ADS_ERROR(rc);
660 goto done;
663 blob = data_blob(scred->bv_val, scred->bv_len);
665 ber_bvfree(scred);
667 #if 0
668 file_save("sasl_spnego.dat", blob.data, blob.length);
669 #endif
671 /* the server sent us the first part of the SPNEGO exchange in the negprot
672 reply */
673 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
674 OIDs[0] == NULL) {
675 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
676 goto done;
678 TALLOC_FREE(given_principal);
680 /* make sure the server understands kerberos */
681 for (i=0;OIDs[i];i++) {
682 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
683 #ifdef HAVE_KRB5
684 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
685 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
686 got_kerberos_mechanism = True;
688 #endif
689 talloc_free(OIDs[i]);
692 status = ads_generate_service_principal(ads, &p);
693 if (!ADS_ERR_OK(status)) {
694 goto done;
697 #ifdef HAVE_KRB5
698 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
699 got_kerberos_mechanism)
701 mech = "KRB5";
703 if (ads->auth.password == NULL ||
704 ads->auth.password[0] == '\0')
707 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
708 CRED_USE_KERBEROS_REQUIRED,
709 p.service, p.hostname,
710 blob);
711 if (ADS_ERR_OK(status)) {
712 ads_free_service_principal(&p);
713 goto done;
716 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
717 "calling kinit\n", ads_errstr(status)));
720 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
722 if (ADS_ERR_OK(status)) {
723 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
724 CRED_USE_KERBEROS_REQUIRED,
725 p.service, p.hostname,
726 blob);
727 if (!ADS_ERR_OK(status)) {
728 DBG_ERR("kinit succeeded but "
729 "SPNEGO bind with Kerberos failed "
730 "for %s/%s - user[%s], realm[%s]: %s\n",
731 p.service, p.hostname,
732 ads->auth.user_name,
733 ads->auth.realm,
734 ads_errstr(status));
738 /* only fallback to NTLMSSP if allowed */
739 if (ADS_ERR_OK(status) ||
740 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
741 goto done;
744 DBG_WARNING("SASL bind with Kerberos failed "
745 "for %s/%s - user[%s], realm[%s]: %s, "
746 "try to fallback to NTLMSSP\n",
747 p.service, p.hostname,
748 ads->auth.user_name,
749 ads->auth.realm,
750 ads_errstr(status));
752 #endif
754 /* lets do NTLMSSP ... this has the big advantage that we don't need
755 to sync clocks, and we don't rely on special versions of the krb5
756 library for HMAC_MD4 encryption */
757 mech = "NTLMSSP";
759 if (!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
760 DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
761 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
762 goto done;
765 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
766 DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
767 " disallowed.\n");
768 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
769 goto done;
772 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
773 CRED_USE_KERBEROS_DISABLED,
774 p.service, p.hostname,
775 data_blob_null);
776 done:
777 if (!ADS_ERR_OK(status)) {
778 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
779 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
780 p.service, p.hostname,
781 ads->auth.user_name,
782 ads->auth.realm,
783 ads_errstr(status)));
785 ads_free_service_principal(&p);
786 TALLOC_FREE(frame);
787 if (blob.data != NULL) {
788 data_blob_free(&blob);
790 return status;
793 /* mapping between SASL mechanisms and functions */
794 static struct {
795 const char *name;
796 ADS_STATUS (*fn)(ADS_STRUCT *);
797 } sasl_mechanisms[] = {
798 {"GSS-SPNEGO", ads_sasl_spnego_bind},
799 {NULL, NULL}
802 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
804 const char *attrs[] = {"supportedSASLMechanisms", NULL};
805 char **values;
806 ADS_STATUS status;
807 int i, j;
808 LDAPMessage *res;
809 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
811 /* get a list of supported SASL mechanisms */
812 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
813 if (!ADS_ERR_OK(status)) return status;
815 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
817 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
818 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
819 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
820 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
821 } else {
822 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
825 /* try our supported mechanisms in order */
826 for (i=0;sasl_mechanisms[i].name;i++) {
827 /* see if the server supports it */
828 for (j=0;values && values[j];j++) {
829 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
830 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
831 retry:
832 status = sasl_mechanisms[i].fn(ads);
833 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
834 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
835 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
837 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
838 "retrying with signing enabled\n"));
839 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
840 goto retry;
842 ldap_value_free(values);
843 ldap_msgfree(res);
844 return status;
849 ldap_value_free(values);
850 ldap_msgfree(res);
851 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
854 #endif /* HAVE_LDAP */