Revert "script/release.sh: use 8 byte gpg key ids"
[Samba.git] / source3 / libads / sasl.c
blob85a2eb00e98a3bedaf55dbb9e35c0e019eb47dfe
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 const char *ccache_name = "MEMORY:ads_sasl_spnego_bind";
753 if (ads->auth.ccache_name != NULL) {
754 ccache_name = ads->auth.ccache_name;
757 if (ads->auth.password == NULL ||
758 ads->auth.password[0] == '\0')
761 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
762 CRED_MUST_USE_KERBEROS,
763 p.service, p.hostname,
764 blob);
765 if (ADS_ERR_OK(status)) {
766 ads_free_service_principal(&p);
767 goto done;
770 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
771 "calling kinit\n", ads_errstr(status)));
774 setenv(KRB5_ENV_CCNAME, ccache_name, 1);
775 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
777 if (ADS_ERR_OK(status)) {
778 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
779 CRED_MUST_USE_KERBEROS,
780 p.service, p.hostname,
781 blob);
782 if (!ADS_ERR_OK(status)) {
783 DEBUG(0,("kinit succeeded but "
784 "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
785 ads_errstr(status)));
789 /* only fallback to NTLMSSP if allowed */
790 if (ADS_ERR_OK(status) ||
791 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
792 goto done;
795 #endif
797 /* lets do NTLMSSP ... this has the big advantage that we don't need
798 to sync clocks, and we don't rely on special versions of the krb5
799 library for HMAC_MD4 encryption */
800 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
801 CRED_DONT_USE_KERBEROS,
802 p.service, p.hostname,
803 data_blob_null);
804 done:
805 ads_free_service_principal(&p);
806 TALLOC_FREE(frame);
807 if (blob.data != NULL) {
808 data_blob_free(&blob);
810 return status;
813 #ifdef HAVE_KRB5
814 #define MAX_GSS_PASSES 3
816 /* this performs a SASL/gssapi bind
817 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
818 is very dependent on correctly configured DNS whereas
819 this routine is much less fragile
820 see RFC2078 and RFC2222 for details
822 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
824 uint32_t minor_status;
825 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
826 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
827 gss_OID mech_type = GSS_C_NULL_OID;
828 gss_buffer_desc output_token, input_token;
829 uint32_t req_flags, ret_flags;
830 int conf_state;
831 struct berval cred;
832 struct berval *scred = NULL;
833 int i=0;
834 int gss_rc, rc;
835 uint8_t *p;
836 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
837 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
838 ADS_STATUS status;
840 input_token.value = NULL;
841 input_token.length = 0;
843 status = ads_init_gssapi_cred(ads, &gss_cred);
844 if (!ADS_ERR_OK(status)) {
845 goto failed;
849 * Note: here we always ask the gssapi for sign and seal
850 * as this is negotiated later after the mutal
851 * authentication
853 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
855 for (i=0; i < MAX_GSS_PASSES; i++) {
856 gss_rc = gss_init_sec_context(&minor_status,
857 gss_cred,
858 &context_handle,
859 serv_name,
860 mech_type,
861 req_flags,
863 NULL,
864 &input_token,
865 NULL,
866 &output_token,
867 &ret_flags,
868 NULL);
869 if (scred) {
870 ber_bvfree(scred);
871 scred = NULL;
873 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
874 status = ADS_ERROR_GSS(gss_rc, minor_status);
875 goto failed;
878 cred.bv_val = (char *)output_token.value;
879 cred.bv_len = output_token.length;
881 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
882 &scred);
883 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
884 status = ADS_ERROR(rc);
885 goto failed;
888 if (output_token.value) {
889 gss_release_buffer(&minor_status, &output_token);
892 if (scred) {
893 input_token.value = scred->bv_val;
894 input_token.length = scred->bv_len;
895 } else {
896 input_token.value = NULL;
897 input_token.length = 0;
900 if (gss_rc == 0) break;
903 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
904 &conf_state,NULL);
905 if (scred) {
906 ber_bvfree(scred);
907 scred = NULL;
909 if (gss_rc) {
910 status = ADS_ERROR_GSS(gss_rc, minor_status);
911 goto failed;
914 p = (uint8_t *)output_token.value;
916 #if 0
917 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
918 #endif
920 if (p) {
921 wrap_type = CVAL(p,0);
922 SCVAL(p,0,0);
923 max_msg_size = RIVAL(p,0);
926 gss_release_buffer(&minor_status, &output_token);
928 if (!(wrap_type & ads->ldap.wrap_type)) {
930 * the server doesn't supports the wrap
931 * type we want :-(
933 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
934 ads->ldap.wrap_type, wrap_type));
935 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
936 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
937 goto failed;
940 /* 0x58 is the minimum windows accepts */
941 if (max_msg_size < 0x58) {
942 max_msg_size = 0x58;
945 output_token.length = 4;
946 output_token.value = SMB_MALLOC(output_token.length);
947 if (!output_token.value) {
948 output_token.length = 0;
949 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
950 goto failed;
952 p = (uint8_t *)output_token.value;
954 RSIVAL(p,0,max_msg_size);
955 SCVAL(p,0,ads->ldap.wrap_type);
958 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
959 * but using ads->config.bind_path is the wrong! It should be
960 * the DN of the user object!
962 * w2k3 gives an error when we send an incorrect DN, but sending nothing
963 * is ok and matches the information flow used in GSS-SPNEGO.
966 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
967 &output_token, /* used as *input* here. */
968 &conf_state,
969 &input_token); /* Used as *output* here. */
970 if (gss_rc) {
971 status = ADS_ERROR_GSS(gss_rc, minor_status);
972 output_token.length = 0;
973 SAFE_FREE(output_token.value);
974 goto failed;
977 /* We've finished with output_token. */
978 SAFE_FREE(output_token.value);
979 output_token.length = 0;
981 cred.bv_val = (char *)input_token.value;
982 cred.bv_len = input_token.length;
984 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
985 &scred);
986 gss_release_buffer(&minor_status, &input_token);
987 status = ADS_ERROR(rc);
988 if (!ADS_ERR_OK(status)) {
989 goto failed;
992 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
993 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
994 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
995 GSS_C_QOP_DEFAULT,
996 max_msg_size, &ads->ldap.out.max_unwrapped);
997 if (gss_rc) {
998 status = ADS_ERROR_GSS(gss_rc, minor_status);
999 goto failed;
1002 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1003 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1004 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
1005 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, 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;
1030 const char *ccache_name = "MEMORY:ads_sasl_gssapi_do_bind";
1032 status = ads_generate_service_principal(ads, &p);
1033 if (!ADS_ERR_OK(status)) {
1034 return status;
1037 if (ads->auth.password == NULL ||
1038 ads->auth.password[0] == '\0') {
1039 status = ads_sasl_gssapi_do_bind(ads, p.name);
1040 if (ADS_ERR_OK(status)) {
1041 ads_free_service_principal(&p);
1042 return status;
1045 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1046 "calling kinit\n", ads_errstr(status)));
1049 if (ads->auth.ccache_name != NULL) {
1050 ccache_name = ads->auth.ccache_name;
1052 setenv(KRB5_ENV_CCNAME, ccache_name, 1);
1053 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1055 if (ADS_ERR_OK(status)) {
1056 status = ads_sasl_gssapi_do_bind(ads, p.name);
1059 ads_free_service_principal(&p);
1061 return status;
1064 #endif /* HAVE_KRB5 */
1066 /* mapping between SASL mechanisms and functions */
1067 static struct {
1068 const char *name;
1069 ADS_STATUS (*fn)(ADS_STRUCT *);
1070 } sasl_mechanisms[] = {
1071 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1072 #ifdef HAVE_KRB5
1073 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1074 #endif
1075 {NULL, NULL}
1078 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1080 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1081 char **values;
1082 ADS_STATUS status;
1083 int i, j;
1084 LDAPMessage *res;
1086 /* get a list of supported SASL mechanisms */
1087 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1088 if (!ADS_ERR_OK(status)) return status;
1090 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1092 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1093 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1094 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1095 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1096 } else {
1097 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1100 /* try our supported mechanisms in order */
1101 for (i=0;sasl_mechanisms[i].name;i++) {
1102 /* see if the server supports it */
1103 for (j=0;values && values[j];j++) {
1104 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1105 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1106 retry:
1107 status = sasl_mechanisms[i].fn(ads);
1108 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1109 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1110 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1112 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1113 "retrying with signing enabled\n"));
1114 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1115 goto retry;
1117 ldap_value_free(values);
1118 ldap_msgfree(res);
1119 return status;
1124 ldap_value_free(values);
1125 ldap_msgfree(res);
1126 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1129 #endif /* HAVE_LDAP */