auth log: Add tests for anonymous bind and SamLogon
[Samba.git] / source3 / libads / sasl.c
blobab79f70f77316f396cad9f93b796fba29ed9318a
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"
31 #ifdef HAVE_LDAP
33 static ADS_STATUS ads_sasl_gensec_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
35 struct gensec_security *gensec_security =
36 talloc_get_type_abort(ads->ldap.wrap_private_data,
37 struct gensec_security);
38 NTSTATUS nt_status;
39 DATA_BLOB unwrapped, wrapped;
40 TALLOC_CTX *frame = talloc_stackframe();
42 unwrapped = data_blob_const(buf, len);
44 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
45 if (!NT_STATUS_IS_OK(nt_status)) {
46 TALLOC_FREE(frame);
47 return ADS_ERROR_NT(nt_status);
50 if ((ads->ldap.out.size - 4) < wrapped.length) {
51 TALLOC_FREE(frame);
52 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
55 /* copy the wrapped blob to the right location */
56 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
58 /* set how many bytes must be written to the underlying socket */
59 ads->ldap.out.left = 4 + wrapped.length;
61 TALLOC_FREE(frame);
63 return ADS_SUCCESS;
66 static ADS_STATUS ads_sasl_gensec_unwrap(ADS_STRUCT *ads)
68 struct gensec_security *gensec_security =
69 talloc_get_type_abort(ads->ldap.wrap_private_data,
70 struct gensec_security);
71 NTSTATUS nt_status;
72 DATA_BLOB unwrapped, wrapped;
73 TALLOC_CTX *frame = talloc_stackframe();
75 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
77 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
78 if (!NT_STATUS_IS_OK(nt_status)) {
79 TALLOC_FREE(frame);
80 return ADS_ERROR_NT(nt_status);
83 if (wrapped.length < unwrapped.length) {
84 TALLOC_FREE(frame);
85 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
88 /* copy the wrapped blob to the right location */
89 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
91 /* set how many bytes must be written to the underlying socket */
92 ads->ldap.in.left = unwrapped.length;
93 ads->ldap.in.ofs = 4;
95 TALLOC_FREE(frame);
97 return ADS_SUCCESS;
100 static void ads_sasl_gensec_disconnect(ADS_STRUCT *ads)
102 struct gensec_security *gensec_security =
103 talloc_get_type_abort(ads->ldap.wrap_private_data,
104 struct gensec_security);
106 TALLOC_FREE(gensec_security);
108 ads->ldap.wrap_ops = NULL;
109 ads->ldap.wrap_private_data = NULL;
112 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
113 .name = "gensec",
114 .wrap = ads_sasl_gensec_wrap,
115 .unwrap = ads_sasl_gensec_unwrap,
116 .disconnect = ads_sasl_gensec_disconnect
120 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
121 we fit on one socket??)
123 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
124 const char *sasl,
125 enum credentials_use_kerberos krb5_state,
126 const char *target_service,
127 const char *target_hostname,
128 const DATA_BLOB server_blob)
130 DATA_BLOB blob_in = data_blob_null;
131 DATA_BLOB blob_out = data_blob_null;
132 int rc;
133 NTSTATUS nt_status;
134 ADS_STATUS status;
135 struct auth_generic_state *auth_generic_state;
136 bool use_spnego_principal = lp_client_use_spnego_principal();
137 const char *sasl_list[] = { sasl, NULL };
138 NTTIME end_nt_time;
140 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
141 if (!NT_STATUS_IS_OK(nt_status)) {
142 return ADS_ERROR_NT(nt_status);
145 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
146 return ADS_ERROR_NT(nt_status);
148 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
149 return ADS_ERROR_NT(nt_status);
151 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
152 return ADS_ERROR_NT(nt_status);
155 if (server_blob.length == 0) {
156 use_spnego_principal = false;
159 if (krb5_state == CRED_DONT_USE_KERBEROS) {
160 use_spnego_principal = false;
163 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
164 krb5_state);
166 if (target_service != NULL) {
167 nt_status = gensec_set_target_service(
168 auth_generic_state->gensec_security,
169 target_service);
170 if (!NT_STATUS_IS_OK(nt_status)) {
171 return ADS_ERROR_NT(nt_status);
175 if (target_hostname != NULL) {
176 nt_status = gensec_set_target_hostname(
177 auth_generic_state->gensec_security,
178 target_hostname);
179 if (!NT_STATUS_IS_OK(nt_status)) {
180 return ADS_ERROR_NT(nt_status);
184 if (target_service != NULL && target_hostname != NULL) {
185 use_spnego_principal = false;
188 switch (ads->ldap.wrap_type) {
189 case ADS_SASLWRAP_TYPE_SEAL:
190 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
191 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
192 break;
193 case ADS_SASLWRAP_TYPE_SIGN:
194 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
195 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
196 } else {
198 * windows servers are broken with sign only,
199 * so we let the NTLMSSP backend to seal here,
200 * via GENSEC_FEATURE_LDAP_STYLE.
202 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
203 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
205 break;
206 case ADS_SASLWRAP_TYPE_PLAIN:
207 break;
210 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
211 sasl_list);
212 if (!NT_STATUS_IS_OK(nt_status)) {
213 return ADS_ERROR_NT(nt_status);
216 rc = LDAP_SASL_BIND_IN_PROGRESS;
217 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
218 if (use_spnego_principal) {
219 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
220 if (blob_in.length == 0) {
221 TALLOC_FREE(auth_generic_state);
222 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
224 } else {
225 blob_in = data_blob_null;
227 blob_out = data_blob_null;
229 while (true) {
230 struct berval cred, *scred = NULL;
232 nt_status = gensec_update(auth_generic_state->gensec_security,
233 talloc_tos(), blob_in, &blob_out);
234 data_blob_free(&blob_in);
235 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
236 && !NT_STATUS_IS_OK(nt_status))
238 TALLOC_FREE(auth_generic_state);
239 data_blob_free(&blob_out);
240 return ADS_ERROR_NT(nt_status);
243 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
244 break;
247 cred.bv_val = (char *)blob_out.data;
248 cred.bv_len = blob_out.length;
249 scred = NULL;
250 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
251 data_blob_free(&blob_out);
252 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
253 if (scred) {
254 ber_bvfree(scred);
257 TALLOC_FREE(auth_generic_state);
258 return ADS_ERROR(rc);
260 if (scred) {
261 blob_in = data_blob_talloc(talloc_tos(),
262 scred->bv_val,
263 scred->bv_len);
264 if (blob_in.length != scred->bv_len) {
265 ber_bvfree(scred);
266 TALLOC_FREE(auth_generic_state);
267 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
269 ber_bvfree(scred);
270 } else {
271 blob_in = data_blob_null;
273 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
274 break;
278 data_blob_free(&blob_in);
279 data_blob_free(&blob_out);
281 if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
282 bool ok;
284 ok = gensec_have_feature(auth_generic_state->gensec_security,
285 GENSEC_FEATURE_SEAL);
286 if (!ok) {
287 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
288 TALLOC_FREE(auth_generic_state);
289 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
292 ok = gensec_have_feature(auth_generic_state->gensec_security,
293 GENSEC_FEATURE_SIGN);
294 if (!ok) {
295 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
296 TALLOC_FREE(auth_generic_state);
297 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
300 } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
301 bool ok;
303 ok = gensec_have_feature(auth_generic_state->gensec_security,
304 GENSEC_FEATURE_SIGN);
305 if (!ok) {
306 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
307 TALLOC_FREE(auth_generic_state);
308 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
312 ads->auth.tgs_expire = LONG_MAX;
313 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
314 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
315 struct timeval tv;
316 nttime_to_timeval(&tv, end_nt_time);
317 ads->auth.tgs_expire = tv.tv_sec;
320 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
321 size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security);
322 ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security);
324 ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
326 * Note that we have to truncate this to 0x2C
327 * (taken from a capture with LDAP unbind), as the
328 * signature size is not constant for Kerberos with
329 * arcfour-hmac-md5.
331 ads->ldap.in.min_wrapped = MIN(ads->ldap.out.sig_size, 0x2C);
332 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
333 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gensec_ops, auth_generic_state->gensec_security);
334 if (!ADS_ERR_OK(status)) {
335 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
336 ads_errstr(status)));
337 TALLOC_FREE(auth_generic_state);
338 return status;
340 /* Only keep the gensec_security element around long-term */
341 talloc_steal(NULL, auth_generic_state->gensec_security);
343 TALLOC_FREE(auth_generic_state);
345 return ADS_ERROR(rc);
348 #ifdef HAVE_KRB5
349 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
351 ADS_STATUS status;
352 krb5_context kctx;
353 krb5_error_code kerr;
354 krb5_ccache kccache = NULL;
355 uint32_t maj, min;
357 *cred = GSS_C_NO_CREDENTIAL;
359 if (!ads->auth.ccache_name) {
360 return ADS_SUCCESS;
363 kerr = krb5_init_context(&kctx);
364 if (kerr) {
365 return ADS_ERROR_KRB5(kerr);
368 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
369 if (kerr) {
370 status = ADS_ERROR_KRB5(kerr);
371 goto done;
374 maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
375 if (maj != GSS_S_COMPLETE) {
376 status = ADS_ERROR_GSS(maj, min);
377 goto done;
380 status = ADS_SUCCESS;
382 done:
383 if (!ADS_ERR_OK(status) && kccache != NULL) {
384 krb5_cc_close(kctx, kccache);
386 krb5_free_context(kctx);
387 return status;
390 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
392 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
393 ADS_STATUS status;
394 int gss_rc;
395 uint32_t minor_status;
396 gss_buffer_desc unwrapped, wrapped;
397 int conf_req_flag, conf_state;
399 unwrapped.value = buf;
400 unwrapped.length = len;
402 /* for now request sign and seal */
403 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
405 gss_rc = gss_wrap(&minor_status, context_handle,
406 conf_req_flag, GSS_C_QOP_DEFAULT,
407 &unwrapped, &conf_state,
408 &wrapped);
409 status = ADS_ERROR_GSS(gss_rc, minor_status);
410 if (!ADS_ERR_OK(status)) return status;
412 if (conf_req_flag && conf_state == 0) {
413 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
416 if ((ads->ldap.out.size - 4) < wrapped.length) {
417 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
420 /* copy the wrapped blob to the right location */
421 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
423 /* set how many bytes must be written to the underlying socket */
424 ads->ldap.out.left = 4 + wrapped.length;
426 gss_release_buffer(&minor_status, &wrapped);
428 return ADS_SUCCESS;
431 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
433 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
434 ADS_STATUS status;
435 int gss_rc;
436 uint32_t minor_status;
437 gss_buffer_desc unwrapped, wrapped;
438 int conf_state;
440 wrapped.value = ads->ldap.in.buf + 4;
441 wrapped.length = ads->ldap.in.ofs - 4;
443 gss_rc = gss_unwrap(&minor_status, context_handle,
444 &wrapped, &unwrapped,
445 &conf_state, GSS_C_QOP_DEFAULT);
446 status = ADS_ERROR_GSS(gss_rc, minor_status);
447 if (!ADS_ERR_OK(status)) return status;
449 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
450 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
453 if (wrapped.length < unwrapped.length) {
454 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
457 /* copy the wrapped blob to the right location */
458 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
460 /* set how many bytes must be written to the underlying socket */
461 ads->ldap.in.left = unwrapped.length;
462 ads->ldap.in.ofs = 4;
464 gss_release_buffer(&minor_status, &unwrapped);
466 return ADS_SUCCESS;
469 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
471 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
472 uint32_t minor_status;
474 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
476 ads->ldap.wrap_ops = NULL;
477 ads->ldap.wrap_private_data = NULL;
480 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
481 .name = "gssapi",
482 .wrap = ads_sasl_gssapi_wrap,
483 .unwrap = ads_sasl_gssapi_unwrap,
484 .disconnect = ads_sasl_gssapi_disconnect
487 #endif /* HAVE_KRB5 */
489 #ifdef HAVE_KRB5
490 struct ads_service_principal {
491 char *service;
492 char *hostname;
493 char *string;
494 #ifdef HAVE_KRB5
495 gss_name_t name;
496 #endif
499 static void ads_free_service_principal(struct ads_service_principal *p)
501 SAFE_FREE(p->service);
502 SAFE_FREE(p->hostname);
503 SAFE_FREE(p->string);
505 #ifdef HAVE_KRB5
506 if (p->name) {
507 uint32_t minor_status;
508 gss_release_name(&minor_status, &p->name);
510 #endif
511 ZERO_STRUCTP(p);
514 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
515 char **service,
516 char **hostname,
517 char **principal)
519 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
520 char *princ = NULL;
521 TALLOC_CTX *frame;
522 char *server = NULL;
523 char *realm = NULL;
524 int rc;
526 frame = talloc_stackframe();
527 if (frame == NULL) {
528 return ADS_ERROR(LDAP_NO_MEMORY);
531 if (ads->server.realm && ads->server.ldap_server) {
532 server = strlower_talloc(frame, ads->server.ldap_server);
533 if (server == NULL) {
534 goto out;
537 realm = strupper_talloc(frame, ads->server.realm);
538 if (realm == NULL) {
539 goto out;
543 * If we got a name which is bigger than a NetBIOS name,
544 * but isn't a FQDN, create one.
546 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
547 char *dnsdomain;
549 dnsdomain = strlower_talloc(frame, ads->server.realm);
550 if (dnsdomain == NULL) {
551 goto out;
554 server = talloc_asprintf(frame,
555 "%s.%s",
556 server, dnsdomain);
557 if (server == NULL) {
558 goto out;
561 } else if (ads->config.realm && ads->config.ldap_server_name) {
562 server = strlower_talloc(frame, ads->config.ldap_server_name);
563 if (server == NULL) {
564 goto out;
567 realm = strupper_talloc(frame, ads->config.realm);
568 if (realm == NULL) {
569 goto out;
573 * If we got a name which is bigger than a NetBIOS name,
574 * but isn't a FQDN, create one.
576 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
577 char *dnsdomain;
579 dnsdomain = strlower_talloc(frame, ads->server.realm);
580 if (dnsdomain == NULL) {
581 goto out;
584 server = talloc_asprintf(frame,
585 "%s.%s",
586 server, dnsdomain);
587 if (server == NULL) {
588 goto out;
593 if (server == NULL || realm == NULL) {
594 goto out;
597 *service = SMB_STRDUP("ldap");
598 if (*service == NULL) {
599 status = ADS_ERROR(LDAP_PARAM_ERROR);
600 goto out;
602 *hostname = SMB_STRDUP(server);
603 if (*hostname == NULL) {
604 SAFE_FREE(*service);
605 status = ADS_ERROR(LDAP_PARAM_ERROR);
606 goto out;
608 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
609 if (rc == -1 || princ == NULL) {
610 SAFE_FREE(*service);
611 SAFE_FREE(*hostname);
612 status = ADS_ERROR(LDAP_PARAM_ERROR);
613 goto out;
616 *principal = princ;
618 status = ADS_SUCCESS;
619 out:
620 TALLOC_FREE(frame);
621 return status;
624 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
625 struct ads_service_principal *p)
627 ADS_STATUS status;
628 #ifdef HAVE_KRB5
629 gss_buffer_desc input_name;
630 /* GSS_KRB5_NT_PRINCIPAL_NAME */
631 gss_OID_desc nt_principal =
632 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
633 uint32_t minor_status;
634 int gss_rc;
635 #endif
637 ZERO_STRUCTP(p);
639 status = ads_guess_target(ads,
640 &p->service,
641 &p->hostname,
642 &p->string);
643 if (!ADS_ERR_OK(status)) {
644 return status;
647 #ifdef HAVE_KRB5
648 input_name.value = p->string;
649 input_name.length = strlen(p->string);
651 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
652 if (gss_rc) {
653 ads_free_service_principal(p);
654 return ADS_ERROR_GSS(gss_rc, minor_status);
656 #endif
658 return ADS_SUCCESS;
661 #endif /* HAVE_KRB5 */
664 this performs a SASL/SPNEGO bind
666 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
668 TALLOC_CTX *frame = talloc_stackframe();
669 struct ads_service_principal p = {0};
670 struct berval *scred=NULL;
671 int rc, i;
672 ADS_STATUS status;
673 DATA_BLOB blob = data_blob_null;
674 char *given_principal = NULL;
675 char *OIDs[ASN1_MAX_OIDS];
676 #ifdef HAVE_KRB5
677 bool got_kerberos_mechanism = False;
678 #endif
679 const char *mech = NULL;
681 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
683 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
684 status = ADS_ERROR(rc);
685 goto done;
688 blob = data_blob(scred->bv_val, scred->bv_len);
690 ber_bvfree(scred);
692 #if 0
693 file_save("sasl_spnego.dat", blob.data, blob.length);
694 #endif
696 /* the server sent us the first part of the SPNEGO exchange in the negprot
697 reply */
698 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
699 OIDs[0] == NULL) {
700 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
701 goto done;
703 TALLOC_FREE(given_principal);
705 /* make sure the server understands kerberos */
706 for (i=0;OIDs[i];i++) {
707 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
708 #ifdef HAVE_KRB5
709 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
710 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
711 got_kerberos_mechanism = True;
713 #endif
714 talloc_free(OIDs[i]);
717 status = ads_generate_service_principal(ads, &p);
718 if (!ADS_ERR_OK(status)) {
719 goto done;
722 #ifdef HAVE_KRB5
723 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
724 got_kerberos_mechanism)
726 mech = "KRB5";
728 if (ads->auth.password == NULL ||
729 ads->auth.password[0] == '\0')
732 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
733 CRED_MUST_USE_KERBEROS,
734 p.service, p.hostname,
735 blob);
736 if (ADS_ERR_OK(status)) {
737 ads_free_service_principal(&p);
738 goto done;
741 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
742 "calling kinit\n", ads_errstr(status)));
745 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
747 if (ADS_ERR_OK(status)) {
748 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
749 CRED_MUST_USE_KERBEROS,
750 p.service, p.hostname,
751 blob);
752 if (!ADS_ERR_OK(status)) {
753 DEBUG(0,("kinit succeeded but "
754 "ads_sasl_spnego_gensec_bind(KRB5) failed "
755 "for %s/%s with user[%s] realm[%s]: %s\n",
756 p.service, p.hostname,
757 ads->auth.user_name,
758 ads->auth.realm,
759 ads_errstr(status)));
763 /* only fallback to NTLMSSP if allowed */
764 if (ADS_ERR_OK(status) ||
765 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
766 goto done;
769 DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
770 "for %s/%s with user[%s] realm[%s]: %s, "
771 "fallback to NTLMSSP\n",
772 p.service, p.hostname,
773 ads->auth.user_name,
774 ads->auth.realm,
775 ads_errstr(status)));
777 #endif
779 /* lets do NTLMSSP ... this has the big advantage that we don't need
780 to sync clocks, and we don't rely on special versions of the krb5
781 library for HMAC_MD4 encryption */
782 mech = "NTLMSSP";
783 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
784 CRED_DONT_USE_KERBEROS,
785 p.service, p.hostname,
786 data_blob_null);
787 done:
788 if (!ADS_ERR_OK(status)) {
789 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
790 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
791 p.service, p.hostname,
792 ads->auth.user_name,
793 ads->auth.realm,
794 ads_errstr(status)));
796 ads_free_service_principal(&p);
797 TALLOC_FREE(frame);
798 if (blob.data != NULL) {
799 data_blob_free(&blob);
801 return status;
804 #ifdef HAVE_KRB5
805 #define MAX_GSS_PASSES 3
807 /* this performs a SASL/gssapi bind
808 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
809 is very dependent on correctly configured DNS whereas
810 this routine is much less fragile
811 see RFC2078 and RFC2222 for details
813 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
815 uint32_t minor_status;
816 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
817 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
818 gss_OID mech_type = GSS_C_NULL_OID;
819 gss_buffer_desc output_token, input_token;
820 uint32_t req_flags, ret_flags;
821 int conf_state;
822 struct berval cred;
823 struct berval *scred = NULL;
824 int i=0;
825 int gss_rc, rc;
826 uint8_t *p;
827 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
828 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
829 ADS_STATUS status;
831 input_token.value = NULL;
832 input_token.length = 0;
834 status = ads_init_gssapi_cred(ads, &gss_cred);
835 if (!ADS_ERR_OK(status)) {
836 goto failed;
840 * Note: here we always ask the gssapi for sign and seal
841 * as this is negotiated later after the mutal
842 * authentication
844 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
846 for (i=0; i < MAX_GSS_PASSES; i++) {
847 gss_rc = gss_init_sec_context(&minor_status,
848 gss_cred,
849 &context_handle,
850 serv_name,
851 mech_type,
852 req_flags,
854 NULL,
855 &input_token,
856 NULL,
857 &output_token,
858 &ret_flags,
859 NULL);
860 if (scred) {
861 ber_bvfree(scred);
862 scred = NULL;
864 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
865 status = ADS_ERROR_GSS(gss_rc, minor_status);
866 goto failed;
869 cred.bv_val = (char *)output_token.value;
870 cred.bv_len = output_token.length;
872 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
873 &scred);
874 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
875 status = ADS_ERROR(rc);
876 goto failed;
879 if (output_token.value) {
880 gss_release_buffer(&minor_status, &output_token);
883 if (scred) {
884 input_token.value = scred->bv_val;
885 input_token.length = scred->bv_len;
886 } else {
887 input_token.value = NULL;
888 input_token.length = 0;
891 if (gss_rc == 0) break;
894 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
895 &conf_state,NULL);
896 if (scred) {
897 ber_bvfree(scred);
898 scred = NULL;
900 if (gss_rc) {
901 status = ADS_ERROR_GSS(gss_rc, minor_status);
902 goto failed;
905 p = (uint8_t *)output_token.value;
907 #if 0
908 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
909 #endif
911 if (p) {
912 wrap_type = CVAL(p,0);
913 SCVAL(p,0,0);
914 max_msg_size = RIVAL(p,0);
917 gss_release_buffer(&minor_status, &output_token);
919 if (!(wrap_type & ads->ldap.wrap_type)) {
921 * the server doesn't supports the wrap
922 * type we want :-(
924 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
925 ads->ldap.wrap_type, wrap_type));
926 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
927 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
928 goto failed;
931 /* 0x58 is the minimum windows accepts */
932 if (max_msg_size < 0x58) {
933 max_msg_size = 0x58;
936 output_token.length = 4;
937 output_token.value = SMB_MALLOC(output_token.length);
938 if (!output_token.value) {
939 output_token.length = 0;
940 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
941 goto failed;
943 p = (uint8_t *)output_token.value;
945 RSIVAL(p,0,max_msg_size);
946 SCVAL(p,0,ads->ldap.wrap_type);
949 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
950 * but using ads->config.bind_path is the wrong! It should be
951 * the DN of the user object!
953 * w2k3 gives an error when we send an incorrect DN, but sending nothing
954 * is ok and matches the information flow used in GSS-SPNEGO.
957 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
958 &output_token, /* used as *input* here. */
959 &conf_state,
960 &input_token); /* Used as *output* here. */
961 if (gss_rc) {
962 status = ADS_ERROR_GSS(gss_rc, minor_status);
963 output_token.length = 0;
964 SAFE_FREE(output_token.value);
965 goto failed;
968 /* We've finished with output_token. */
969 SAFE_FREE(output_token.value);
970 output_token.length = 0;
972 cred.bv_val = (char *)input_token.value;
973 cred.bv_len = input_token.length;
975 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
976 &scred);
977 gss_release_buffer(&minor_status, &input_token);
978 status = ADS_ERROR(rc);
979 if (!ADS_ERR_OK(status)) {
980 goto failed;
983 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
984 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
985 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
986 GSS_C_QOP_DEFAULT,
987 max_msg_size, &ads->ldap.out.max_unwrapped);
988 if (gss_rc) {
989 status = ADS_ERROR_GSS(gss_rc, minor_status);
990 goto failed;
993 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
994 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
995 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
996 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
997 if (!ADS_ERR_OK(status)) {
998 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
999 ads_errstr(status)));
1000 goto failed;
1002 /* make sure we don't free context_handle */
1003 context_handle = GSS_C_NO_CONTEXT;
1006 failed:
1007 if (gss_cred != GSS_C_NO_CREDENTIAL)
1008 gss_release_cred(&minor_status, &gss_cred);
1009 if (context_handle != GSS_C_NO_CONTEXT)
1010 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1012 if(scred)
1013 ber_bvfree(scred);
1014 return status;
1017 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1019 ADS_STATUS status;
1020 struct ads_service_principal p;
1022 status = ads_generate_service_principal(ads, &p);
1023 if (!ADS_ERR_OK(status)) {
1024 return status;
1027 if (ads->auth.password == NULL ||
1028 ads->auth.password[0] == '\0') {
1029 status = ads_sasl_gssapi_do_bind(ads, p.name);
1030 if (ADS_ERR_OK(status)) {
1031 ads_free_service_principal(&p);
1032 return status;
1035 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1036 "calling kinit\n", ads_errstr(status)));
1039 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1041 if (ADS_ERR_OK(status)) {
1042 status = ads_sasl_gssapi_do_bind(ads, p.name);
1045 ads_free_service_principal(&p);
1047 return status;
1050 #endif /* HAVE_KRB5 */
1052 /* mapping between SASL mechanisms and functions */
1053 static struct {
1054 const char *name;
1055 ADS_STATUS (*fn)(ADS_STRUCT *);
1056 } sasl_mechanisms[] = {
1057 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1058 #ifdef HAVE_KRB5
1059 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1060 #endif
1061 {NULL, NULL}
1064 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1066 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1067 char **values;
1068 ADS_STATUS status;
1069 int i, j;
1070 LDAPMessage *res;
1072 /* get a list of supported SASL mechanisms */
1073 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1074 if (!ADS_ERR_OK(status)) return status;
1076 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1078 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1079 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1080 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1081 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1082 } else {
1083 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1086 /* try our supported mechanisms in order */
1087 for (i=0;sasl_mechanisms[i].name;i++) {
1088 /* see if the server supports it */
1089 for (j=0;values && values[j];j++) {
1090 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1091 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1092 retry:
1093 status = sasl_mechanisms[i].fn(ads);
1094 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1095 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1096 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1098 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1099 "retrying with signing enabled\n"));
1100 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1101 goto retry;
1103 ldap_value_free(values);
1104 ldap_msgfree(res);
1105 return status;
1110 ldap_value_free(values);
1111 ldap_msgfree(res);
1112 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1115 #endif /* HAVE_LDAP */