s3:libads: don't use MEMORY:ads_sasl_spnego_bind nor set "KRB5CCNAME"
[Samba.git] / source3 / libads / sasl.c
blob39c60c3e14dd755ce458d33b1d787b43f911aa10
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 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
369 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
370 if (kerr) {
371 status = ADS_ERROR_KRB5(kerr);
372 goto done;
375 maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
376 if (maj != GSS_S_COMPLETE) {
377 status = ADS_ERROR_GSS(maj, min);
378 goto done;
380 #else
381 /* We need to fallback to overriding the default creds.
382 * This operation is not thread safe as it changes the process
383 * environment variable, but we do not have any better option
384 * with older kerberos libraries */
386 const char *oldccname = NULL;
388 oldccname = getenv("KRB5CCNAME");
389 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
391 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
392 NULL, GSS_C_INITIATE, cred, NULL, NULL);
394 if (oldccname) {
395 setenv("KRB5CCNAME", oldccname, 1);
396 } else {
397 unsetenv("KRB5CCNAME");
400 if (maj != GSS_S_COMPLETE) {
401 status = ADS_ERROR_GSS(maj, min);
402 goto done;
405 #endif
407 status = ADS_SUCCESS;
409 done:
410 if (!ADS_ERR_OK(status) && kccache != NULL) {
411 krb5_cc_close(kctx, kccache);
413 krb5_free_context(kctx);
414 return status;
417 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
419 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
420 ADS_STATUS status;
421 int gss_rc;
422 uint32_t minor_status;
423 gss_buffer_desc unwrapped, wrapped;
424 int conf_req_flag, conf_state;
426 unwrapped.value = buf;
427 unwrapped.length = len;
429 /* for now request sign and seal */
430 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
432 gss_rc = gss_wrap(&minor_status, context_handle,
433 conf_req_flag, GSS_C_QOP_DEFAULT,
434 &unwrapped, &conf_state,
435 &wrapped);
436 status = ADS_ERROR_GSS(gss_rc, minor_status);
437 if (!ADS_ERR_OK(status)) return status;
439 if (conf_req_flag && conf_state == 0) {
440 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
443 if ((ads->ldap.out.size - 4) < wrapped.length) {
444 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
447 /* copy the wrapped blob to the right location */
448 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
450 /* set how many bytes must be written to the underlying socket */
451 ads->ldap.out.left = 4 + wrapped.length;
453 gss_release_buffer(&minor_status, &wrapped);
455 return ADS_SUCCESS;
458 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
460 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
461 ADS_STATUS status;
462 int gss_rc;
463 uint32_t minor_status;
464 gss_buffer_desc unwrapped, wrapped;
465 int conf_state;
467 wrapped.value = ads->ldap.in.buf + 4;
468 wrapped.length = ads->ldap.in.ofs - 4;
470 gss_rc = gss_unwrap(&minor_status, context_handle,
471 &wrapped, &unwrapped,
472 &conf_state, GSS_C_QOP_DEFAULT);
473 status = ADS_ERROR_GSS(gss_rc, minor_status);
474 if (!ADS_ERR_OK(status)) return status;
476 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
477 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
480 if (wrapped.length < unwrapped.length) {
481 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
484 /* copy the wrapped blob to the right location */
485 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
487 /* set how many bytes must be written to the underlying socket */
488 ads->ldap.in.left = unwrapped.length;
489 ads->ldap.in.ofs = 4;
491 gss_release_buffer(&minor_status, &unwrapped);
493 return ADS_SUCCESS;
496 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
498 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
499 uint32_t minor_status;
501 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
503 ads->ldap.wrap_ops = NULL;
504 ads->ldap.wrap_private_data = NULL;
507 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
508 .name = "gssapi",
509 .wrap = ads_sasl_gssapi_wrap,
510 .unwrap = ads_sasl_gssapi_unwrap,
511 .disconnect = ads_sasl_gssapi_disconnect
514 #endif /* HAVE_KRB5 */
516 #ifdef HAVE_KRB5
517 struct ads_service_principal {
518 char *service;
519 char *hostname;
520 char *string;
521 #ifdef HAVE_KRB5
522 gss_name_t name;
523 #endif
526 static void ads_free_service_principal(struct ads_service_principal *p)
528 SAFE_FREE(p->service);
529 SAFE_FREE(p->hostname);
530 SAFE_FREE(p->string);
532 #ifdef HAVE_KRB5
533 if (p->name) {
534 uint32_t minor_status;
535 gss_release_name(&minor_status, &p->name);
537 #endif
538 ZERO_STRUCTP(p);
541 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
542 char **service,
543 char **hostname,
544 char **principal)
546 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
547 char *princ = NULL;
548 TALLOC_CTX *frame;
549 char *server = NULL;
550 char *realm = NULL;
551 int rc;
553 frame = talloc_stackframe();
554 if (frame == NULL) {
555 return ADS_ERROR(LDAP_NO_MEMORY);
558 if (ads->server.realm && ads->server.ldap_server) {
559 server = strlower_talloc(frame, ads->server.ldap_server);
560 if (server == NULL) {
561 goto out;
564 realm = strupper_talloc(frame, ads->server.realm);
565 if (realm == NULL) {
566 goto out;
570 * If we got a name which is bigger than a NetBIOS name,
571 * but isn't a FQDN, create one.
573 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
574 char *dnsdomain;
576 dnsdomain = strlower_talloc(frame, ads->server.realm);
577 if (dnsdomain == NULL) {
578 goto out;
581 server = talloc_asprintf(frame,
582 "%s.%s",
583 server, dnsdomain);
584 if (server == NULL) {
585 goto out;
588 } else if (ads->config.realm && ads->config.ldap_server_name) {
589 server = strlower_talloc(frame, ads->config.ldap_server_name);
590 if (server == NULL) {
591 goto out;
594 realm = strupper_talloc(frame, ads->config.realm);
595 if (realm == NULL) {
596 goto out;
600 * If we got a name which is bigger than a NetBIOS name,
601 * but isn't a FQDN, create one.
603 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
604 char *dnsdomain;
606 dnsdomain = strlower_talloc(frame, ads->server.realm);
607 if (dnsdomain == NULL) {
608 goto out;
611 server = talloc_asprintf(frame,
612 "%s.%s",
613 server, dnsdomain);
614 if (server == NULL) {
615 goto out;
620 if (server == NULL || realm == NULL) {
621 goto out;
624 *service = SMB_STRDUP("ldap");
625 if (*service == NULL) {
626 status = ADS_ERROR(LDAP_PARAM_ERROR);
627 goto out;
629 *hostname = SMB_STRDUP(server);
630 if (*hostname == NULL) {
631 SAFE_FREE(*service);
632 status = ADS_ERROR(LDAP_PARAM_ERROR);
633 goto out;
635 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
636 if (rc == -1 || princ == NULL) {
637 SAFE_FREE(*service);
638 SAFE_FREE(*hostname);
639 status = ADS_ERROR(LDAP_PARAM_ERROR);
640 goto out;
643 *principal = princ;
645 status = ADS_SUCCESS;
646 out:
647 TALLOC_FREE(frame);
648 return status;
651 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
652 struct ads_service_principal *p)
654 ADS_STATUS status;
655 #ifdef HAVE_KRB5
656 gss_buffer_desc input_name;
657 /* GSS_KRB5_NT_PRINCIPAL_NAME */
658 gss_OID_desc nt_principal =
659 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
660 uint32_t minor_status;
661 int gss_rc;
662 #endif
664 ZERO_STRUCTP(p);
666 status = ads_guess_target(ads,
667 &p->service,
668 &p->hostname,
669 &p->string);
670 if (!ADS_ERR_OK(status)) {
671 return status;
674 #ifdef HAVE_KRB5
675 input_name.value = p->string;
676 input_name.length = strlen(p->string);
678 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
679 if (gss_rc) {
680 ads_free_service_principal(p);
681 return ADS_ERROR_GSS(gss_rc, minor_status);
683 #endif
685 return ADS_SUCCESS;
688 #endif /* HAVE_KRB5 */
691 this performs a SASL/SPNEGO bind
693 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
695 TALLOC_CTX *frame = talloc_stackframe();
696 struct ads_service_principal p = {0};
697 struct berval *scred=NULL;
698 int rc, i;
699 ADS_STATUS status;
700 DATA_BLOB blob = data_blob_null;
701 char *given_principal = NULL;
702 char *OIDs[ASN1_MAX_OIDS];
703 #ifdef HAVE_KRB5
704 bool got_kerberos_mechanism = False;
705 #endif
707 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
709 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
710 status = ADS_ERROR(rc);
711 goto done;
714 blob = data_blob(scred->bv_val, scred->bv_len);
716 ber_bvfree(scred);
718 #if 0
719 file_save("sasl_spnego.dat", blob.data, blob.length);
720 #endif
722 /* the server sent us the first part of the SPNEGO exchange in the negprot
723 reply */
724 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
725 OIDs[0] == NULL) {
726 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
727 goto done;
729 TALLOC_FREE(given_principal);
731 /* make sure the server understands kerberos */
732 for (i=0;OIDs[i];i++) {
733 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
734 #ifdef HAVE_KRB5
735 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
736 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
737 got_kerberos_mechanism = True;
739 #endif
740 talloc_free(OIDs[i]);
743 status = ads_generate_service_principal(ads, &p);
744 if (!ADS_ERR_OK(status)) {
745 goto done;
748 #ifdef HAVE_KRB5
749 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
750 got_kerberos_mechanism)
752 if (ads->auth.password == NULL ||
753 ads->auth.password[0] == '\0')
756 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
757 CRED_MUST_USE_KERBEROS,
758 p.service, p.hostname,
759 blob);
760 if (ADS_ERR_OK(status)) {
761 ads_free_service_principal(&p);
762 goto done;
765 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
766 "calling kinit\n", ads_errstr(status)));
769 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
771 if (ADS_ERR_OK(status)) {
772 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
773 CRED_MUST_USE_KERBEROS,
774 p.service, p.hostname,
775 blob);
776 if (!ADS_ERR_OK(status)) {
777 DEBUG(0,("kinit succeeded but "
778 "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
779 ads_errstr(status)));
783 /* only fallback to NTLMSSP if allowed */
784 if (ADS_ERR_OK(status) ||
785 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
786 goto done;
789 #endif
791 /* lets do NTLMSSP ... this has the big advantage that we don't need
792 to sync clocks, and we don't rely on special versions of the krb5
793 library for HMAC_MD4 encryption */
794 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
795 CRED_DONT_USE_KERBEROS,
796 p.service, p.hostname,
797 data_blob_null);
798 done:
799 ads_free_service_principal(&p);
800 TALLOC_FREE(frame);
801 if (blob.data != NULL) {
802 data_blob_free(&blob);
804 return status;
807 #ifdef HAVE_KRB5
808 #define MAX_GSS_PASSES 3
810 /* this performs a SASL/gssapi bind
811 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
812 is very dependent on correctly configured DNS whereas
813 this routine is much less fragile
814 see RFC2078 and RFC2222 for details
816 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
818 uint32_t minor_status;
819 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
820 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
821 gss_OID mech_type = GSS_C_NULL_OID;
822 gss_buffer_desc output_token, input_token;
823 uint32_t req_flags, ret_flags;
824 int conf_state;
825 struct berval cred;
826 struct berval *scred = NULL;
827 int i=0;
828 int gss_rc, rc;
829 uint8_t *p;
830 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
831 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
832 ADS_STATUS status;
834 input_token.value = NULL;
835 input_token.length = 0;
837 status = ads_init_gssapi_cred(ads, &gss_cred);
838 if (!ADS_ERR_OK(status)) {
839 goto failed;
843 * Note: here we always ask the gssapi for sign and seal
844 * as this is negotiated later after the mutal
845 * authentication
847 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
849 for (i=0; i < MAX_GSS_PASSES; i++) {
850 gss_rc = gss_init_sec_context(&minor_status,
851 gss_cred,
852 &context_handle,
853 serv_name,
854 mech_type,
855 req_flags,
857 NULL,
858 &input_token,
859 NULL,
860 &output_token,
861 &ret_flags,
862 NULL);
863 if (scred) {
864 ber_bvfree(scred);
865 scred = NULL;
867 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
868 status = ADS_ERROR_GSS(gss_rc, minor_status);
869 goto failed;
872 cred.bv_val = (char *)output_token.value;
873 cred.bv_len = output_token.length;
875 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
876 &scred);
877 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
878 status = ADS_ERROR(rc);
879 goto failed;
882 if (output_token.value) {
883 gss_release_buffer(&minor_status, &output_token);
886 if (scred) {
887 input_token.value = scred->bv_val;
888 input_token.length = scred->bv_len;
889 } else {
890 input_token.value = NULL;
891 input_token.length = 0;
894 if (gss_rc == 0) break;
897 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
898 &conf_state,NULL);
899 if (scred) {
900 ber_bvfree(scred);
901 scred = NULL;
903 if (gss_rc) {
904 status = ADS_ERROR_GSS(gss_rc, minor_status);
905 goto failed;
908 p = (uint8_t *)output_token.value;
910 #if 0
911 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
912 #endif
914 if (p) {
915 wrap_type = CVAL(p,0);
916 SCVAL(p,0,0);
917 max_msg_size = RIVAL(p,0);
920 gss_release_buffer(&minor_status, &output_token);
922 if (!(wrap_type & ads->ldap.wrap_type)) {
924 * the server doesn't supports the wrap
925 * type we want :-(
927 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
928 ads->ldap.wrap_type, wrap_type));
929 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
930 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
931 goto failed;
934 /* 0x58 is the minimum windows accepts */
935 if (max_msg_size < 0x58) {
936 max_msg_size = 0x58;
939 output_token.length = 4;
940 output_token.value = SMB_MALLOC(output_token.length);
941 if (!output_token.value) {
942 output_token.length = 0;
943 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
944 goto failed;
946 p = (uint8_t *)output_token.value;
948 RSIVAL(p,0,max_msg_size);
949 SCVAL(p,0,ads->ldap.wrap_type);
952 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
953 * but using ads->config.bind_path is the wrong! It should be
954 * the DN of the user object!
956 * w2k3 gives an error when we send an incorrect DN, but sending nothing
957 * is ok and matches the information flow used in GSS-SPNEGO.
960 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
961 &output_token, /* used as *input* here. */
962 &conf_state,
963 &input_token); /* Used as *output* here. */
964 if (gss_rc) {
965 status = ADS_ERROR_GSS(gss_rc, minor_status);
966 output_token.length = 0;
967 SAFE_FREE(output_token.value);
968 goto failed;
971 /* We've finished with output_token. */
972 SAFE_FREE(output_token.value);
973 output_token.length = 0;
975 cred.bv_val = (char *)input_token.value;
976 cred.bv_len = input_token.length;
978 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
979 &scred);
980 gss_release_buffer(&minor_status, &input_token);
981 status = ADS_ERROR(rc);
982 if (!ADS_ERR_OK(status)) {
983 goto failed;
986 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
987 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
988 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
989 GSS_C_QOP_DEFAULT,
990 max_msg_size, &ads->ldap.out.max_unwrapped);
991 if (gss_rc) {
992 status = ADS_ERROR_GSS(gss_rc, minor_status);
993 goto failed;
996 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
997 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
998 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
999 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1000 if (!ADS_ERR_OK(status)) {
1001 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1002 ads_errstr(status)));
1003 goto failed;
1005 /* make sure we don't free context_handle */
1006 context_handle = GSS_C_NO_CONTEXT;
1009 failed:
1010 if (gss_cred != GSS_C_NO_CREDENTIAL)
1011 gss_release_cred(&minor_status, &gss_cred);
1012 if (context_handle != GSS_C_NO_CONTEXT)
1013 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1015 if(scred)
1016 ber_bvfree(scred);
1017 return status;
1020 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1022 ADS_STATUS status;
1023 struct ads_service_principal p;
1025 status = ads_generate_service_principal(ads, &p);
1026 if (!ADS_ERR_OK(status)) {
1027 return status;
1030 if (ads->auth.password == NULL ||
1031 ads->auth.password[0] == '\0') {
1032 status = ads_sasl_gssapi_do_bind(ads, p.name);
1033 if (ADS_ERR_OK(status)) {
1034 ads_free_service_principal(&p);
1035 return status;
1038 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1039 "calling kinit\n", ads_errstr(status)));
1042 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1044 if (ADS_ERR_OK(status)) {
1045 status = ads_sasl_gssapi_do_bind(ads, p.name);
1048 ads_free_service_principal(&p);
1050 return status;
1053 #endif /* HAVE_KRB5 */
1055 /* mapping between SASL mechanisms and functions */
1056 static struct {
1057 const char *name;
1058 ADS_STATUS (*fn)(ADS_STRUCT *);
1059 } sasl_mechanisms[] = {
1060 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1061 #ifdef HAVE_KRB5
1062 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1063 #endif
1064 {NULL, NULL}
1067 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1069 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1070 char **values;
1071 ADS_STATUS status;
1072 int i, j;
1073 LDAPMessage *res;
1075 /* get a list of supported SASL mechanisms */
1076 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1077 if (!ADS_ERR_OK(status)) return status;
1079 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1081 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1082 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1083 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1084 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1085 } else {
1086 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1089 /* try our supported mechanisms in order */
1090 for (i=0;sasl_mechanisms[i].name;i++) {
1091 /* see if the server supports it */
1092 for (j=0;values && values[j];j++) {
1093 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1094 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1095 retry:
1096 status = sasl_mechanisms[i].fn(ads);
1097 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1098 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1099 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1101 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1102 "retrying with signing enabled\n"));
1103 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1104 goto retry;
1106 ldap_value_free(values);
1107 ldap_msgfree(res);
1108 return status;
1113 ldap_value_free(values);
1114 ldap_msgfree(res);
1115 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1118 #endif /* HAVE_LDAP */