WHATSNEW: Fix typo.
[Samba.git] / source3 / libads / sasl.c
blob7f7b790810ce4dc76ab8bf5d8dcc48e53fdfcc7d
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(struct ads_saslwrap *wrap,
34 uint8_t *buf, uint32_t len)
36 struct gensec_security *gensec_security =
37 talloc_get_type_abort(wrap->wrap_private_data,
38 struct gensec_security);
39 NTSTATUS nt_status;
40 DATA_BLOB unwrapped, wrapped;
41 TALLOC_CTX *frame = talloc_stackframe();
43 unwrapped = data_blob_const(buf, len);
45 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
46 if (!NT_STATUS_IS_OK(nt_status)) {
47 TALLOC_FREE(frame);
48 return ADS_ERROR_NT(nt_status);
51 if ((wrap->out.size - 4) < wrapped.length) {
52 TALLOC_FREE(frame);
53 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
56 /* copy the wrapped blob to the right location */
57 memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
59 /* set how many bytes must be written to the underlying socket */
60 wrap->out.left = 4 + wrapped.length;
62 TALLOC_FREE(frame);
64 return ADS_SUCCESS;
67 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
69 struct gensec_security *gensec_security =
70 talloc_get_type_abort(wrap->wrap_private_data,
71 struct gensec_security);
72 NTSTATUS nt_status;
73 DATA_BLOB unwrapped, wrapped;
74 TALLOC_CTX *frame = talloc_stackframe();
76 wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
78 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
79 if (!NT_STATUS_IS_OK(nt_status)) {
80 TALLOC_FREE(frame);
81 return ADS_ERROR_NT(nt_status);
84 if (wrapped.length < unwrapped.length) {
85 TALLOC_FREE(frame);
86 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
89 /* copy the wrapped blob to the right location */
90 memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
92 /* set how many bytes must be written to the underlying socket */
93 wrap->in.left = unwrapped.length;
94 wrap->in.ofs = 4;
96 TALLOC_FREE(frame);
98 return ADS_SUCCESS;
101 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
103 struct gensec_security *gensec_security =
104 talloc_get_type_abort(wrap->wrap_private_data,
105 struct gensec_security);
107 TALLOC_FREE(gensec_security);
109 wrap->wrap_ops = NULL;
110 wrap->wrap_private_data = NULL;
113 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
114 .name = "gensec",
115 .wrap = ads_sasl_gensec_wrap,
116 .unwrap = ads_sasl_gensec_unwrap,
117 .disconnect = ads_sasl_gensec_disconnect
121 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
122 we fit on one socket??)
124 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
125 const char *sasl,
126 enum credentials_use_kerberos krb5_state,
127 const char *target_service,
128 const char *target_hostname,
129 const DATA_BLOB server_blob)
131 DATA_BLOB blob_in = data_blob_null;
132 DATA_BLOB blob_out = data_blob_null;
133 int rc;
134 NTSTATUS nt_status;
135 ADS_STATUS status;
136 struct auth_generic_state *auth_generic_state;
137 bool use_spnego_principal = lp_client_use_spnego_principal();
138 const char *sasl_list[] = { sasl, NULL };
139 NTTIME end_nt_time;
140 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
142 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
143 if (!NT_STATUS_IS_OK(nt_status)) {
144 return ADS_ERROR_NT(nt_status);
147 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
148 return ADS_ERROR_NT(nt_status);
150 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
151 return ADS_ERROR_NT(nt_status);
153 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
154 return ADS_ERROR_NT(nt_status);
157 if (server_blob.length == 0) {
158 use_spnego_principal = false;
161 if (krb5_state == CRED_DONT_USE_KERBEROS) {
162 use_spnego_principal = false;
165 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
166 krb5_state);
168 if (target_service != NULL) {
169 nt_status = gensec_set_target_service(
170 auth_generic_state->gensec_security,
171 target_service);
172 if (!NT_STATUS_IS_OK(nt_status)) {
173 return ADS_ERROR_NT(nt_status);
177 if (target_hostname != NULL) {
178 nt_status = gensec_set_target_hostname(
179 auth_generic_state->gensec_security,
180 target_hostname);
181 if (!NT_STATUS_IS_OK(nt_status)) {
182 return ADS_ERROR_NT(nt_status);
186 if (target_service != NULL && target_hostname != NULL) {
187 use_spnego_principal = false;
190 switch (wrap->wrap_type) {
191 case ADS_SASLWRAP_TYPE_SEAL:
192 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
193 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
194 break;
195 case ADS_SASLWRAP_TYPE_SIGN:
196 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
197 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
198 } else {
200 * windows servers are broken with sign only,
201 * so we let the NTLMSSP backend to seal here,
202 * via GENSEC_FEATURE_LDAP_STYLE.
204 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
205 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
207 break;
208 case ADS_SASLWRAP_TYPE_PLAIN:
209 break;
212 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
213 sasl_list);
214 if (!NT_STATUS_IS_OK(nt_status)) {
215 return ADS_ERROR_NT(nt_status);
218 rc = LDAP_SASL_BIND_IN_PROGRESS;
219 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
220 if (use_spnego_principal) {
221 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
222 if (blob_in.length == 0) {
223 TALLOC_FREE(auth_generic_state);
224 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
226 } else {
227 blob_in = data_blob_null;
229 blob_out = data_blob_null;
231 while (true) {
232 struct berval cred, *scred = NULL;
234 nt_status = gensec_update(auth_generic_state->gensec_security,
235 talloc_tos(), blob_in, &blob_out);
236 data_blob_free(&blob_in);
237 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
238 && !NT_STATUS_IS_OK(nt_status))
240 TALLOC_FREE(auth_generic_state);
241 data_blob_free(&blob_out);
242 return ADS_ERROR_NT(nt_status);
245 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
246 break;
249 cred.bv_val = (char *)blob_out.data;
250 cred.bv_len = blob_out.length;
251 scred = NULL;
252 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
253 data_blob_free(&blob_out);
254 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
255 if (scred) {
256 ber_bvfree(scred);
259 TALLOC_FREE(auth_generic_state);
260 return ADS_ERROR(rc);
262 if (scred) {
263 blob_in = data_blob_talloc(talloc_tos(),
264 scred->bv_val,
265 scred->bv_len);
266 if (blob_in.length != scred->bv_len) {
267 ber_bvfree(scred);
268 TALLOC_FREE(auth_generic_state);
269 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
271 ber_bvfree(scred);
272 } else {
273 blob_in = data_blob_null;
275 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
276 break;
280 data_blob_free(&blob_in);
281 data_blob_free(&blob_out);
283 if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
284 bool ok;
286 ok = gensec_have_feature(auth_generic_state->gensec_security,
287 GENSEC_FEATURE_SEAL);
288 if (!ok) {
289 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
290 TALLOC_FREE(auth_generic_state);
291 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
294 ok = gensec_have_feature(auth_generic_state->gensec_security,
295 GENSEC_FEATURE_SIGN);
296 if (!ok) {
297 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
298 TALLOC_FREE(auth_generic_state);
299 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
302 } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
303 bool ok;
305 ok = gensec_have_feature(auth_generic_state->gensec_security,
306 GENSEC_FEATURE_SIGN);
307 if (!ok) {
308 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
309 TALLOC_FREE(auth_generic_state);
310 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
314 ads->auth.tgs_expire = LONG_MAX;
315 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
316 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
317 struct timeval tv;
318 nttime_to_timeval(&tv, end_nt_time);
319 ads->auth.tgs_expire = tv.tv_sec;
322 if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
323 size_t max_wrapped =
324 gensec_max_wrapped_size(auth_generic_state->gensec_security);
325 wrap->out.max_unwrapped =
326 gensec_max_input_size(auth_generic_state->gensec_security);
328 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
330 * Note that we have to truncate this to 0x2C
331 * (taken from a capture with LDAP unbind), as the
332 * signature size is not constant for Kerberos with
333 * arcfour-hmac-md5.
335 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
336 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
337 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
338 &ads_sasl_gensec_ops,
339 auth_generic_state->gensec_security);
340 if (!ADS_ERR_OK(status)) {
341 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
342 ads_errstr(status)));
343 TALLOC_FREE(auth_generic_state);
344 return status;
346 /* Only keep the gensec_security element around long-term */
347 talloc_steal(NULL, auth_generic_state->gensec_security);
349 TALLOC_FREE(auth_generic_state);
351 return ADS_ERROR(rc);
354 #ifdef HAVE_KRB5
355 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
357 ADS_STATUS status;
358 krb5_context kctx;
359 krb5_error_code kerr;
360 krb5_ccache kccache = NULL;
361 uint32_t maj, min;
363 *cred = GSS_C_NO_CREDENTIAL;
365 if (!ads->auth.ccache_name) {
366 return ADS_SUCCESS;
369 kerr = krb5_init_context(&kctx);
370 if (kerr) {
371 return ADS_ERROR_KRB5(kerr);
374 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
375 if (kerr) {
376 status = ADS_ERROR_KRB5(kerr);
377 goto done;
380 maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
381 if (maj != GSS_S_COMPLETE) {
382 status = ADS_ERROR_GSS(maj, min);
383 goto done;
386 status = ADS_SUCCESS;
388 done:
389 if (!ADS_ERR_OK(status) && kccache != NULL) {
390 krb5_cc_close(kctx, kccache);
392 krb5_free_context(kctx);
393 return status;
396 static ADS_STATUS ads_sasl_gssapi_wrap(struct ads_saslwrap *wrap, uint8_t *buf, uint32_t len)
398 gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
399 ADS_STATUS status;
400 int gss_rc;
401 uint32_t minor_status;
402 gss_buffer_desc unwrapped, wrapped;
403 int conf_req_flag, conf_state;
405 unwrapped.value = buf;
406 unwrapped.length = len;
408 /* for now request sign and seal */
409 conf_req_flag = (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL);
411 gss_rc = gss_wrap(&minor_status, context_handle,
412 conf_req_flag, GSS_C_QOP_DEFAULT,
413 &unwrapped, &conf_state,
414 &wrapped);
415 status = ADS_ERROR_GSS(gss_rc, minor_status);
416 if (!ADS_ERR_OK(status)) return status;
418 if (conf_req_flag && conf_state == 0) {
419 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
422 if ((wrap->out.size - 4) < wrapped.length) {
423 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
426 /* copy the wrapped blob to the right location */
427 memcpy(wrap->out.buf + 4, wrapped.value, wrapped.length);
429 /* set how many bytes must be written to the underlying socket */
430 wrap->out.left = 4 + wrapped.length;
432 gss_release_buffer(&minor_status, &wrapped);
434 return ADS_SUCCESS;
437 static ADS_STATUS ads_sasl_gssapi_unwrap(struct ads_saslwrap *wrap)
439 gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
440 ADS_STATUS status;
441 int gss_rc;
442 uint32_t minor_status;
443 gss_buffer_desc unwrapped, wrapped;
444 int conf_state;
446 wrapped.value = wrap->in.buf + 4;
447 wrapped.length = wrap->in.ofs - 4;
449 gss_rc = gss_unwrap(&minor_status, context_handle,
450 &wrapped, &unwrapped,
451 &conf_state, GSS_C_QOP_DEFAULT);
452 status = ADS_ERROR_GSS(gss_rc, minor_status);
453 if (!ADS_ERR_OK(status)) return status;
455 if (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
456 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
459 if (wrapped.length < unwrapped.length) {
460 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
463 /* copy the wrapped blob to the right location */
464 memcpy(wrap->in.buf + 4, unwrapped.value, unwrapped.length);
466 /* set how many bytes must be written to the underlying socket */
467 wrap->in.left = unwrapped.length;
468 wrap->in.ofs = 4;
470 gss_release_buffer(&minor_status, &unwrapped);
472 return ADS_SUCCESS;
475 static void ads_sasl_gssapi_disconnect(struct ads_saslwrap *wrap)
477 gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
478 uint32_t minor_status;
480 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
482 wrap->wrap_ops = NULL;
483 wrap->wrap_private_data = NULL;
486 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
487 .name = "gssapi",
488 .wrap = ads_sasl_gssapi_wrap,
489 .unwrap = ads_sasl_gssapi_unwrap,
490 .disconnect = ads_sasl_gssapi_disconnect
493 #endif /* HAVE_KRB5 */
495 #ifdef HAVE_KRB5
496 struct ads_service_principal {
497 char *service;
498 char *hostname;
499 char *string;
500 #ifdef HAVE_KRB5
501 gss_name_t name;
502 #endif
505 static void ads_free_service_principal(struct ads_service_principal *p)
507 SAFE_FREE(p->service);
508 SAFE_FREE(p->hostname);
509 SAFE_FREE(p->string);
511 #ifdef HAVE_KRB5
512 if (p->name) {
513 uint32_t minor_status;
514 gss_release_name(&minor_status, &p->name);
516 #endif
517 ZERO_STRUCTP(p);
520 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
521 char **service,
522 char **hostname,
523 char **principal)
525 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
526 char *princ = NULL;
527 TALLOC_CTX *frame;
528 char *server = NULL;
529 char *realm = NULL;
530 int rc;
532 frame = talloc_stackframe();
533 if (frame == NULL) {
534 return ADS_ERROR(LDAP_NO_MEMORY);
537 if (ads->server.realm && ads->server.ldap_server) {
538 server = strlower_talloc(frame, ads->server.ldap_server);
539 if (server == NULL) {
540 goto out;
543 realm = strupper_talloc(frame, ads->server.realm);
544 if (realm == NULL) {
545 goto out;
549 * If we got a name which is bigger than a NetBIOS name,
550 * but isn't a FQDN, create one.
552 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
553 char *dnsdomain;
555 dnsdomain = strlower_talloc(frame, ads->server.realm);
556 if (dnsdomain == NULL) {
557 goto out;
560 server = talloc_asprintf(frame,
561 "%s.%s",
562 server, dnsdomain);
563 if (server == NULL) {
564 goto out;
567 } else if (ads->config.realm && ads->config.ldap_server_name) {
568 server = strlower_talloc(frame, ads->config.ldap_server_name);
569 if (server == NULL) {
570 goto out;
573 realm = strupper_talloc(frame, ads->config.realm);
574 if (realm == NULL) {
575 goto out;
579 * If we got a name which is bigger than a NetBIOS name,
580 * but isn't a FQDN, create one.
582 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
583 char *dnsdomain;
585 dnsdomain = strlower_talloc(frame, ads->server.realm);
586 if (dnsdomain == NULL) {
587 goto out;
590 server = talloc_asprintf(frame,
591 "%s.%s",
592 server, dnsdomain);
593 if (server == NULL) {
594 goto out;
599 if (server == NULL || realm == NULL) {
600 goto out;
603 *service = SMB_STRDUP("ldap");
604 if (*service == NULL) {
605 status = ADS_ERROR(LDAP_PARAM_ERROR);
606 goto out;
608 *hostname = SMB_STRDUP(server);
609 if (*hostname == NULL) {
610 SAFE_FREE(*service);
611 status = ADS_ERROR(LDAP_PARAM_ERROR);
612 goto out;
614 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
615 if (rc == -1 || princ == NULL) {
616 SAFE_FREE(*service);
617 SAFE_FREE(*hostname);
618 status = ADS_ERROR(LDAP_PARAM_ERROR);
619 goto out;
622 *principal = princ;
624 status = ADS_SUCCESS;
625 out:
626 TALLOC_FREE(frame);
627 return status;
630 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
631 struct ads_service_principal *p)
633 ADS_STATUS status;
634 #ifdef HAVE_KRB5
635 gss_buffer_desc input_name;
636 /* GSS_KRB5_NT_PRINCIPAL_NAME */
637 gss_OID_desc nt_principal =
638 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
639 uint32_t minor_status;
640 int gss_rc;
641 #endif
643 ZERO_STRUCTP(p);
645 status = ads_guess_target(ads,
646 &p->service,
647 &p->hostname,
648 &p->string);
649 if (!ADS_ERR_OK(status)) {
650 return status;
653 #ifdef HAVE_KRB5
654 input_name.value = p->string;
655 input_name.length = strlen(p->string);
657 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
658 if (gss_rc) {
659 ads_free_service_principal(p);
660 return ADS_ERROR_GSS(gss_rc, minor_status);
662 #endif
664 return ADS_SUCCESS;
667 #endif /* HAVE_KRB5 */
670 this performs a SASL/SPNEGO bind
672 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
674 TALLOC_CTX *frame = talloc_stackframe();
675 struct ads_service_principal p = {0};
676 struct berval *scred=NULL;
677 int rc, i;
678 ADS_STATUS status;
679 DATA_BLOB blob = data_blob_null;
680 char *given_principal = NULL;
681 char *OIDs[ASN1_MAX_OIDS];
682 #ifdef HAVE_KRB5
683 bool got_kerberos_mechanism = False;
684 #endif
685 const char *mech = NULL;
687 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
689 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
690 status = ADS_ERROR(rc);
691 goto done;
694 blob = data_blob(scred->bv_val, scred->bv_len);
696 ber_bvfree(scred);
698 #if 0
699 file_save("sasl_spnego.dat", blob.data, blob.length);
700 #endif
702 /* the server sent us the first part of the SPNEGO exchange in the negprot
703 reply */
704 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
705 OIDs[0] == NULL) {
706 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
707 goto done;
709 TALLOC_FREE(given_principal);
711 /* make sure the server understands kerberos */
712 for (i=0;OIDs[i];i++) {
713 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
714 #ifdef HAVE_KRB5
715 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
716 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
717 got_kerberos_mechanism = True;
719 #endif
720 talloc_free(OIDs[i]);
723 status = ads_generate_service_principal(ads, &p);
724 if (!ADS_ERR_OK(status)) {
725 goto done;
728 #ifdef HAVE_KRB5
729 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
730 got_kerberos_mechanism)
732 mech = "KRB5";
734 if (ads->auth.password == NULL ||
735 ads->auth.password[0] == '\0')
738 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
739 CRED_MUST_USE_KERBEROS,
740 p.service, p.hostname,
741 blob);
742 if (ADS_ERR_OK(status)) {
743 ads_free_service_principal(&p);
744 goto done;
747 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
748 "calling kinit\n", ads_errstr(status)));
751 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
753 if (ADS_ERR_OK(status)) {
754 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
755 CRED_MUST_USE_KERBEROS,
756 p.service, p.hostname,
757 blob);
758 if (!ADS_ERR_OK(status)) {
759 DEBUG(0,("kinit succeeded but "
760 "ads_sasl_spnego_gensec_bind(KRB5) failed "
761 "for %s/%s with user[%s] realm[%s]: %s\n",
762 p.service, p.hostname,
763 ads->auth.user_name,
764 ads->auth.realm,
765 ads_errstr(status)));
769 /* only fallback to NTLMSSP if allowed */
770 if (ADS_ERR_OK(status) ||
771 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
772 goto done;
775 DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
776 "for %s/%s with user[%s] realm[%s]: %s, "
777 "fallback to NTLMSSP\n",
778 p.service, p.hostname,
779 ads->auth.user_name,
780 ads->auth.realm,
781 ads_errstr(status)));
783 #endif
785 /* lets do NTLMSSP ... this has the big advantage that we don't need
786 to sync clocks, and we don't rely on special versions of the krb5
787 library for HMAC_MD4 encryption */
788 mech = "NTLMSSP";
789 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
790 CRED_DONT_USE_KERBEROS,
791 p.service, p.hostname,
792 data_blob_null);
793 done:
794 if (!ADS_ERR_OK(status)) {
795 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
796 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
797 p.service, p.hostname,
798 ads->auth.user_name,
799 ads->auth.realm,
800 ads_errstr(status)));
802 ads_free_service_principal(&p);
803 TALLOC_FREE(frame);
804 if (blob.data != NULL) {
805 data_blob_free(&blob);
807 return status;
810 #ifdef HAVE_KRB5
811 #define MAX_GSS_PASSES 3
813 /* this performs a SASL/gssapi bind
814 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
815 is very dependent on correctly configured DNS whereas
816 this routine is much less fragile
817 see RFC2078 and RFC2222 for details
819 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
821 uint32_t minor_status;
822 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
823 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
824 gss_OID mech_type = GSS_C_NULL_OID;
825 gss_buffer_desc output_token, input_token;
826 uint32_t req_flags, ret_flags;
827 int conf_state;
828 struct berval cred;
829 struct berval *scred = NULL;
830 int i=0;
831 int gss_rc, rc;
832 uint8_t *p;
833 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
834 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
835 ADS_STATUS status;
836 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
838 input_token.value = NULL;
839 input_token.length = 0;
841 status = ads_init_gssapi_cred(ads, &gss_cred);
842 if (!ADS_ERR_OK(status)) {
843 goto failed;
847 * Note: here we always ask the gssapi for sign and seal
848 * as this is negotiated later after the mutal
849 * authentication
851 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
853 for (i=0; i < MAX_GSS_PASSES; i++) {
854 gss_rc = gss_init_sec_context(&minor_status,
855 gss_cred,
856 &context_handle,
857 serv_name,
858 mech_type,
859 req_flags,
861 NULL,
862 &input_token,
863 NULL,
864 &output_token,
865 &ret_flags,
866 NULL);
867 if (scred) {
868 ber_bvfree(scred);
869 scred = NULL;
871 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
872 status = ADS_ERROR_GSS(gss_rc, minor_status);
873 goto failed;
876 cred.bv_val = (char *)output_token.value;
877 cred.bv_len = output_token.length;
879 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
880 &scred);
881 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
882 status = ADS_ERROR(rc);
883 goto failed;
886 if (output_token.value) {
887 gss_release_buffer(&minor_status, &output_token);
890 if (scred) {
891 input_token.value = scred->bv_val;
892 input_token.length = scred->bv_len;
893 } else {
894 input_token.value = NULL;
895 input_token.length = 0;
898 if (gss_rc == 0) break;
901 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
902 &conf_state,NULL);
903 if (scred) {
904 ber_bvfree(scred);
905 scred = NULL;
907 if (gss_rc) {
908 status = ADS_ERROR_GSS(gss_rc, minor_status);
909 goto failed;
912 p = (uint8_t *)output_token.value;
914 #if 0
915 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
916 #endif
918 if (p) {
919 wrap_type = CVAL(p,0);
920 SCVAL(p,0,0);
921 max_msg_size = RIVAL(p,0);
924 gss_release_buffer(&minor_status, &output_token);
926 if (!(wrap_type & wrap->wrap_type)) {
928 * the server doesn't supports the wrap
929 * type we want :-(
931 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
932 wrap->wrap_type, wrap_type));
933 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
934 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
935 goto failed;
938 /* 0x58 is the minimum windows accepts */
939 if (max_msg_size < 0x58) {
940 max_msg_size = 0x58;
943 output_token.length = 4;
944 output_token.value = SMB_MALLOC(output_token.length);
945 if (!output_token.value) {
946 output_token.length = 0;
947 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
948 goto failed;
950 p = (uint8_t *)output_token.value;
952 RSIVAL(p,0,max_msg_size);
953 SCVAL(p,0,wrap->wrap_type);
956 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
957 * but using ads->config.bind_path is the wrong! It should be
958 * the DN of the user object!
960 * w2k3 gives an error when we send an incorrect DN, but sending nothing
961 * is ok and matches the information flow used in GSS-SPNEGO.
964 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
965 &output_token, /* used as *input* here. */
966 &conf_state,
967 &input_token); /* Used as *output* here. */
968 if (gss_rc) {
969 status = ADS_ERROR_GSS(gss_rc, minor_status);
970 output_token.length = 0;
971 SAFE_FREE(output_token.value);
972 goto failed;
975 /* We've finished with output_token. */
976 SAFE_FREE(output_token.value);
977 output_token.length = 0;
979 cred.bv_val = (char *)input_token.value;
980 cred.bv_len = input_token.length;
982 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
983 &scred);
984 gss_release_buffer(&minor_status, &input_token);
985 status = ADS_ERROR(rc);
986 if (!ADS_ERR_OK(status)) {
987 goto failed;
990 if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
991 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
992 (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL),
993 GSS_C_QOP_DEFAULT,
994 max_msg_size, &wrap->out.max_unwrapped);
995 if (gss_rc) {
996 status = ADS_ERROR_GSS(gss_rc, minor_status);
997 goto failed;
1000 wrap->out.sig_size = max_msg_size - wrap->out.max_unwrapped;
1001 wrap->in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1002 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
1003 status = ads_setup_sasl_wrapping(wrap->wrap_private_data, ads->ldap.ld,
1004 &ads_sasl_gssapi_ops,
1005 context_handle);
1006 if (!ADS_ERR_OK(status)) {
1007 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1008 ads_errstr(status)));
1009 goto failed;
1011 /* make sure we don't free context_handle */
1012 context_handle = GSS_C_NO_CONTEXT;
1015 failed:
1016 if (gss_cred != GSS_C_NO_CREDENTIAL)
1017 gss_release_cred(&minor_status, &gss_cred);
1018 if (context_handle != GSS_C_NO_CONTEXT)
1019 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1021 if(scred)
1022 ber_bvfree(scred);
1023 return status;
1026 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1028 ADS_STATUS status;
1029 struct ads_service_principal p;
1031 status = ads_generate_service_principal(ads, &p);
1032 if (!ADS_ERR_OK(status)) {
1033 return status;
1036 if (ads->auth.password == NULL ||
1037 ads->auth.password[0] == '\0') {
1038 status = ads_sasl_gssapi_do_bind(ads, p.name);
1039 if (ADS_ERR_OK(status)) {
1040 ads_free_service_principal(&p);
1041 return status;
1044 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1045 "calling kinit\n", ads_errstr(status)));
1048 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1050 if (ADS_ERR_OK(status)) {
1051 status = ads_sasl_gssapi_do_bind(ads, p.name);
1054 ads_free_service_principal(&p);
1056 return status;
1059 #endif /* HAVE_KRB5 */
1061 /* mapping between SASL mechanisms and functions */
1062 static struct {
1063 const char *name;
1064 ADS_STATUS (*fn)(ADS_STRUCT *);
1065 } sasl_mechanisms[] = {
1066 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1067 #ifdef HAVE_KRB5
1068 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1069 #endif
1070 {NULL, NULL}
1073 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1075 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1076 char **values;
1077 ADS_STATUS status;
1078 int i, j;
1079 LDAPMessage *res;
1080 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
1082 /* get a list of supported SASL mechanisms */
1083 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1084 if (!ADS_ERR_OK(status)) return status;
1086 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1088 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1089 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1090 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1091 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1092 } else {
1093 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1096 /* try our supported mechanisms in order */
1097 for (i=0;sasl_mechanisms[i].name;i++) {
1098 /* see if the server supports it */
1099 for (j=0;values && values[j];j++) {
1100 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1101 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1102 retry:
1103 status = sasl_mechanisms[i].fn(ads);
1104 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1105 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1106 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1108 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1109 "retrying with signing enabled\n"));
1110 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1111 goto retry;
1113 ldap_value_free(values);
1114 ldap_msgfree(res);
1115 return status;
1120 ldap_value_free(values);
1121 ldap_msgfree(res);
1122 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1125 #endif /* HAVE_LDAP */