source: vendor/current/source3/libads/sasl.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 28.6 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 ads sasl code
4 Copyright (C) Andrew Tridgell 2001
5
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.
10
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.
15
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/>.
18*/
19
20#include "includes.h"
21#include "../libcli/auth/spnego.h"
22#include "auth/credentials/credentials.h"
23#include "auth/gensec/gensec.h"
24#include "auth_generic.h"
25#include "ads.h"
26#include "smb_krb5.h"
27#include "system/gssapi.h"
28#include "lib/param/loadparm.h"
29#include "krb5_env.h"
30
31#ifdef HAVE_LDAP
32
33static ADS_STATUS ads_sasl_gensec_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
34{
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();
41
42 unwrapped = data_blob_const(buf, len);
43
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);
48 }
49
50 if ((ads->ldap.out.size - 4) < wrapped.length) {
51 TALLOC_FREE(frame);
52 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
53 }
54
55 /* copy the wrapped blob to the right location */
56 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
57
58 /* set how many bytes must be written to the underlying socket */
59 ads->ldap.out.left = 4 + wrapped.length;
60
61 TALLOC_FREE(frame);
62
63 return ADS_SUCCESS;
64}
65
66static ADS_STATUS ads_sasl_gensec_unwrap(ADS_STRUCT *ads)
67{
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();
74
75 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
76
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);
81 }
82
83 if (wrapped.length < unwrapped.length) {
84 TALLOC_FREE(frame);
85 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
86 }
87
88 /* copy the wrapped blob to the right location */
89 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
90
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;
94
95 TALLOC_FREE(frame);
96
97 return ADS_SUCCESS;
98}
99
100static void ads_sasl_gensec_disconnect(ADS_STRUCT *ads)
101{
102 struct gensec_security *gensec_security =
103 talloc_get_type_abort(ads->ldap.wrap_private_data,
104 struct gensec_security);
105
106 TALLOC_FREE(gensec_security);
107
108 ads->ldap.wrap_ops = NULL;
109 ads->ldap.wrap_private_data = NULL;
110}
111
112static 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
117};
118
119/*
120 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
121 we fit on one socket??)
122*/
123static 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)
129{
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;
139
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);
143 }
144
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);
147 }
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);
150 }
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);
153 }
154
155 if (server_blob.length == 0) {
156 use_spnego_principal = false;
157 }
158
159 if (krb5_state == CRED_DONT_USE_KERBEROS) {
160 use_spnego_principal = false;
161 }
162
163 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
164 krb5_state);
165
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);
172 }
173 }
174
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);
181 }
182 }
183
184 if (target_service != NULL && target_hostname != NULL) {
185 use_spnego_principal = false;
186 }
187
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 {
197 /*
198 * windows servers are broken with sign only,
199 * so we let the NTLMSSP backend to seal here,
200 * via GENSEC_FEATURE_LDAP_STYLE.
201 */
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);
204 }
205 break;
206 case ADS_SASLWRAP_TYPE_PLAIN:
207 break;
208 }
209
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);
214 }
215
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);
223 }
224 } else {
225 blob_in = data_blob_null;
226 }
227 blob_out = data_blob_null;
228
229 while (true) {
230 struct berval cred, *scred = NULL;
231
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))
237 {
238 TALLOC_FREE(auth_generic_state);
239 data_blob_free(&blob_out);
240 return ADS_ERROR_NT(nt_status);
241 }
242
243 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
244 break;
245 }
246
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);
255 }
256
257 TALLOC_FREE(auth_generic_state);
258 return ADS_ERROR(rc);
259 }
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);
268 }
269 ber_bvfree(scred);
270 } else {
271 blob_in = data_blob_null;
272 }
273 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
274 break;
275 }
276 }
277
278 data_blob_free(&blob_in);
279 data_blob_free(&blob_out);
280
281 if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
282 bool ok;
283
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);
290 }
291
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);
298 }
299
300 } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
301 bool ok;
302
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);
309 }
310 }
311
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;
318 }
319
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);
323
324 ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
325 /*
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.
330 */
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;
339 }
340 /* Only keep the gensec_security element around long-term */
341 talloc_steal(NULL, auth_generic_state->gensec_security);
342 }
343 TALLOC_FREE(auth_generic_state);
344
345 return ADS_ERROR(rc);
346}
347
348#ifdef HAVE_KRB5
349static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
350{
351 ADS_STATUS status;
352 krb5_context kctx;
353 krb5_error_code kerr;
354 krb5_ccache kccache = NULL;
355 uint32_t maj, min;
356
357 *cred = GSS_C_NO_CREDENTIAL;
358
359 if (!ads->auth.ccache_name) {
360 return ADS_SUCCESS;
361 }
362
363 kerr = krb5_init_context(&kctx);
364 if (kerr) {
365 return ADS_ERROR_KRB5(kerr);
366 }
367
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;
373 }
374
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;
379 }
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 */
385 {
386 const char *oldccname = NULL;
387
388 oldccname = getenv("KRB5CCNAME");
389 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
390
391 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
392 NULL, GSS_C_INITIATE, cred, NULL, NULL);
393
394 if (oldccname) {
395 setenv("KRB5CCNAME", oldccname, 1);
396 } else {
397 unsetenv("KRB5CCNAME");
398 }
399
400 if (maj != GSS_S_COMPLETE) {
401 status = ADS_ERROR_GSS(maj, min);
402 goto done;
403 }
404 }
405#endif
406
407 status = ADS_SUCCESS;
408
409done:
410 if (!ADS_ERR_OK(status) && kccache != NULL) {
411 krb5_cc_close(kctx, kccache);
412 }
413 krb5_free_context(kctx);
414 return status;
415}
416
417static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
418{
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;
425
426 unwrapped.value = buf;
427 unwrapped.length = len;
428
429 /* for now request sign and seal */
430 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
431
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;
438
439 if (conf_req_flag && conf_state == 0) {
440 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
441 }
442
443 if ((ads->ldap.out.size - 4) < wrapped.length) {
444 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
445 }
446
447 /* copy the wrapped blob to the right location */
448 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
449
450 /* set how many bytes must be written to the underlying socket */
451 ads->ldap.out.left = 4 + wrapped.length;
452
453 gss_release_buffer(&minor_status, &wrapped);
454
455 return ADS_SUCCESS;
456}
457
458static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
459{
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;
466
467 wrapped.value = ads->ldap.in.buf + 4;
468 wrapped.length = ads->ldap.in.ofs - 4;
469
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;
475
476 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
477 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
478 }
479
480 if (wrapped.length < unwrapped.length) {
481 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
482 }
483
484 /* copy the wrapped blob to the right location */
485 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
486
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;
490
491 gss_release_buffer(&minor_status, &unwrapped);
492
493 return ADS_SUCCESS;
494}
495
496static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
497{
498 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
499 uint32_t minor_status;
500
501 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
502
503 ads->ldap.wrap_ops = NULL;
504 ads->ldap.wrap_private_data = NULL;
505}
506
507static 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
512};
513
514#endif /* HAVE_KRB5 */
515
516#ifdef HAVE_KRB5
517struct ads_service_principal {
518 char *service;
519 char *hostname;
520 char *string;
521#ifdef HAVE_KRB5
522 gss_name_t name;
523#endif
524};
525
526static void ads_free_service_principal(struct ads_service_principal *p)
527{
528 SAFE_FREE(p->service);
529 SAFE_FREE(p->hostname);
530 SAFE_FREE(p->string);
531
532#ifdef HAVE_KRB5
533 if (p->name) {
534 uint32_t minor_status;
535 gss_release_name(&minor_status, &p->name);
536 }
537#endif
538 ZERO_STRUCTP(p);
539}
540
541static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
542 char **service,
543 char **hostname,
544 char **principal)
545{
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;
552
553 frame = talloc_stackframe();
554 if (frame == NULL) {
555 return ADS_ERROR(LDAP_NO_MEMORY);
556 }
557
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;
562 }
563
564 realm = strupper_talloc(frame, ads->server.realm);
565 if (realm == NULL) {
566 goto out;
567 }
568
569 /*
570 * If we got a name which is bigger than a NetBIOS name,
571 * but isn't a FQDN, create one.
572 */
573 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
574 char *dnsdomain;
575
576 dnsdomain = strlower_talloc(frame, ads->server.realm);
577 if (dnsdomain == NULL) {
578 goto out;
579 }
580
581 server = talloc_asprintf(frame,
582 "%s.%s",
583 server, dnsdomain);
584 if (server == NULL) {
585 goto out;
586 }
587 }
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;
592 }
593
594 realm = strupper_talloc(frame, ads->config.realm);
595 if (realm == NULL) {
596 goto out;
597 }
598
599 /*
600 * If we got a name which is bigger than a NetBIOS name,
601 * but isn't a FQDN, create one.
602 */
603 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
604 char *dnsdomain;
605
606 dnsdomain = strlower_talloc(frame, ads->server.realm);
607 if (dnsdomain == NULL) {
608 goto out;
609 }
610
611 server = talloc_asprintf(frame,
612 "%s.%s",
613 server, dnsdomain);
614 if (server == NULL) {
615 goto out;
616 }
617 }
618 }
619
620 if (server == NULL || realm == NULL) {
621 goto out;
622 }
623
624 *service = SMB_STRDUP("ldap");
625 if (*service == NULL) {
626 status = ADS_ERROR(LDAP_PARAM_ERROR);
627 goto out;
628 }
629 *hostname = SMB_STRDUP(server);
630 if (*hostname == NULL) {
631 SAFE_FREE(*service);
632 status = ADS_ERROR(LDAP_PARAM_ERROR);
633 goto out;
634 }
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;
641 }
642
643 *principal = princ;
644
645 status = ADS_SUCCESS;
646out:
647 TALLOC_FREE(frame);
648 return status;
649}
650
651static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
652 struct ads_service_principal *p)
653{
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
663
664 ZERO_STRUCTP(p);
665
666 status = ads_guess_target(ads,
667 &p->service,
668 &p->hostname,
669 &p->string);
670 if (!ADS_ERR_OK(status)) {
671 return status;
672 }
673
674#ifdef HAVE_KRB5
675 input_name.value = p->string;
676 input_name.length = strlen(p->string);
677
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);
682 }
683#endif
684
685 return ADS_SUCCESS;
686}
687
688#endif /* HAVE_KRB5 */
689
690/*
691 this performs a SASL/SPNEGO bind
692*/
693static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
694{
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
706
707 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
708
709 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
710 status = ADS_ERROR(rc);
711 goto done;
712 }
713
714 blob = data_blob(scred->bv_val, scred->bv_len);
715
716 ber_bvfree(scred);
717
718#if 0
719 file_save("sasl_spnego.dat", blob.data, blob.length);
720#endif
721
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;
728 }
729 TALLOC_FREE(given_principal);
730
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;
738 }
739#endif
740 talloc_free(OIDs[i]);
741 }
742
743 status = ads_generate_service_principal(ads, &p);
744 if (!ADS_ERR_OK(status)) {
745 goto done;
746 }
747
748#ifdef HAVE_KRB5
749 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
750 got_kerberos_mechanism)
751 {
752 if (ads->auth.password == NULL ||
753 ads->auth.password[0] == '\0')
754 {
755
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;
763 }
764
765 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
766 "calling kinit\n", ads_errstr(status)));
767 }
768
769 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
770
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)));
780 }
781 }
782
783 /* only fallback to NTLMSSP if allowed */
784 if (ADS_ERR_OK(status) ||
785 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
786 goto done;
787 }
788 }
789#endif
790
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);
798done:
799 ads_free_service_principal(&p);
800 TALLOC_FREE(frame);
801 if (blob.data != NULL) {
802 data_blob_free(&blob);
803 }
804 return status;
805}
806
807#ifdef HAVE_KRB5
808#define MAX_GSS_PASSES 3
809
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
815*/
816static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
817{
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;
833
834 input_token.value = NULL;
835 input_token.length = 0;
836
837 status = ads_init_gssapi_cred(ads, &gss_cred);
838 if (!ADS_ERR_OK(status)) {
839 goto failed;
840 }
841
842 /*
843 * Note: here we always ask the gssapi for sign and seal
844 * as this is negotiated later after the mutal
845 * authentication
846 */
847 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
848
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,
856 0,
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;
866 }
867 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
868 status = ADS_ERROR_GSS(gss_rc, minor_status);
869 goto failed;
870 }
871
872 cred.bv_val = (char *)output_token.value;
873 cred.bv_len = output_token.length;
874
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;
880 }
881
882 if (output_token.value) {
883 gss_release_buffer(&minor_status, &output_token);
884 }
885
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;
892 }
893
894 if (gss_rc == 0) break;
895 }
896
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;
902 }
903 if (gss_rc) {
904 status = ADS_ERROR_GSS(gss_rc, minor_status);
905 goto failed;
906 }
907
908 p = (uint8_t *)output_token.value;
909
910#if 0
911 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
912#endif
913
914 if (p) {
915 wrap_type = CVAL(p,0);
916 SCVAL(p,0,0);
917 max_msg_size = RIVAL(p,0);
918 }
919
920 gss_release_buffer(&minor_status, &output_token);
921
922 if (!(wrap_type & ads->ldap.wrap_type)) {
923 /*
924 * the server doesn't supports the wrap
925 * type we want :-(
926 */
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;
932 }
933
934 /* 0x58 is the minimum windows accepts */
935 if (max_msg_size < 0x58) {
936 max_msg_size = 0x58;
937 }
938
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;
945 }
946 p = (uint8_t *)output_token.value;
947
948 RSIVAL(p,0,max_msg_size);
949 SCVAL(p,0,ads->ldap.wrap_type);
950
951 /*
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!
955 *
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.
958 */
959
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;
969 }
970
971 /* We've finished with output_token. */
972 SAFE_FREE(output_token.value);
973 output_token.length = 0;
974
975 cred.bv_val = (char *)input_token.value;
976 cred.bv_len = input_token.length;
977
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;
984 }
985
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;
994 }
995
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;
1004 }
1005 /* make sure we don't free context_handle */
1006 context_handle = GSS_C_NO_CONTEXT;
1007 }
1008
1009failed:
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);
1014
1015 if(scred)
1016 ber_bvfree(scred);
1017 return status;
1018}
1019
1020static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1021{
1022 ADS_STATUS status;
1023 struct ads_service_principal p;
1024
1025 status = ads_generate_service_principal(ads, &p);
1026 if (!ADS_ERR_OK(status)) {
1027 return status;
1028 }
1029
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;
1036 }
1037
1038 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1039 "calling kinit\n", ads_errstr(status)));
1040 }
1041
1042 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1043
1044 if (ADS_ERR_OK(status)) {
1045 status = ads_sasl_gssapi_do_bind(ads, p.name);
1046 }
1047
1048 ads_free_service_principal(&p);
1049
1050 return status;
1051}
1052
1053#endif /* HAVE_KRB5 */
1054
1055/* mapping between SASL mechanisms and functions */
1056static 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}
1065};
1066
1067ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1068{
1069 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1070 char **values;
1071 ADS_STATUS status;
1072 int i, j;
1073 LDAPMessage *res;
1074
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;
1078
1079 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1080
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;
1087 }
1088
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]));
1095retry:
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)
1100 {
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;
1105 }
1106 ldap_value_free(values);
1107 ldap_msgfree(res);
1108 return status;
1109 }
1110 }
1111 }
1112
1113 ldap_value_free(values);
1114 ldap_msgfree(res);
1115 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1116}
1117
1118#endif /* HAVE_LDAP */
1119
Note: See TracBrowser for help on using the repository browser.