Line data Source code
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 : #include "lib/util/asn1.h"
31 :
32 : #ifdef HAVE_LDAP
33 :
34 1606 : static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
35 : uint8_t *buf, uint32_t len)
36 : {
37 0 : struct gensec_security *gensec_security =
38 1606 : talloc_get_type_abort(wrap->wrap_private_data,
39 : struct gensec_security);
40 0 : NTSTATUS nt_status;
41 0 : DATA_BLOB unwrapped, wrapped;
42 1606 : TALLOC_CTX *frame = talloc_stackframe();
43 :
44 1606 : unwrapped = data_blob_const(buf, len);
45 :
46 1606 : nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
47 1606 : if (!NT_STATUS_IS_OK(nt_status)) {
48 0 : TALLOC_FREE(frame);
49 0 : return ADS_ERROR_NT(nt_status);
50 : }
51 :
52 1606 : if ((wrap->out.size - 4) < wrapped.length) {
53 0 : TALLOC_FREE(frame);
54 0 : return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
55 : }
56 :
57 : /* copy the wrapped blob to the right location */
58 1606 : memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
59 :
60 : /* set how many bytes must be written to the underlying socket */
61 1606 : wrap->out.left = 4 + wrapped.length;
62 :
63 1606 : TALLOC_FREE(frame);
64 :
65 1606 : return ADS_SUCCESS;
66 : }
67 :
68 1299 : static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
69 : {
70 0 : struct gensec_security *gensec_security =
71 1299 : talloc_get_type_abort(wrap->wrap_private_data,
72 : struct gensec_security);
73 0 : NTSTATUS nt_status;
74 0 : DATA_BLOB unwrapped, wrapped;
75 1299 : TALLOC_CTX *frame = talloc_stackframe();
76 :
77 1299 : wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
78 :
79 1299 : nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
80 1299 : if (!NT_STATUS_IS_OK(nt_status)) {
81 0 : TALLOC_FREE(frame);
82 0 : return ADS_ERROR_NT(nt_status);
83 : }
84 :
85 1299 : if (wrapped.length < unwrapped.length) {
86 0 : TALLOC_FREE(frame);
87 0 : return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
88 : }
89 :
90 : /* copy the wrapped blob to the right location */
91 1299 : memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
92 :
93 : /* set how many bytes must be written to the underlying socket */
94 1299 : wrap->in.left = unwrapped.length;
95 1299 : wrap->in.ofs = 4;
96 :
97 1299 : TALLOC_FREE(frame);
98 :
99 1299 : return ADS_SUCCESS;
100 : }
101 :
102 307 : static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
103 : {
104 0 : struct gensec_security *gensec_security =
105 307 : talloc_get_type_abort(wrap->wrap_private_data,
106 : struct gensec_security);
107 :
108 307 : TALLOC_FREE(gensec_security);
109 :
110 307 : wrap->wrap_ops = NULL;
111 307 : wrap->wrap_private_data = NULL;
112 307 : }
113 :
114 : static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
115 : .name = "gensec",
116 : .wrap = ads_sasl_gensec_wrap,
117 : .unwrap = ads_sasl_gensec_unwrap,
118 : .disconnect = ads_sasl_gensec_disconnect
119 : };
120 :
121 : /*
122 : perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
123 : we fit on one socket??)
124 : */
125 311 : static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
126 : const char *sasl,
127 : enum credentials_use_kerberos krb5_state,
128 : const char *target_service,
129 : const char *target_hostname,
130 : const DATA_BLOB server_blob)
131 : {
132 311 : DATA_BLOB blob_in = data_blob_null;
133 311 : DATA_BLOB blob_out = data_blob_null;
134 0 : int rc;
135 0 : NTSTATUS nt_status;
136 0 : ADS_STATUS status;
137 0 : struct auth_generic_state *auth_generic_state;
138 311 : bool use_spnego_principal = lp_client_use_spnego_principal();
139 311 : const char *sasl_list[] = { sasl, NULL };
140 0 : NTTIME end_nt_time;
141 311 : struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
142 :
143 311 : nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
144 311 : if (!NT_STATUS_IS_OK(nt_status)) {
145 0 : return ADS_ERROR_NT(nt_status);
146 : }
147 :
148 311 : if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
149 0 : return ADS_ERROR_NT(nt_status);
150 : }
151 311 : if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
152 0 : return ADS_ERROR_NT(nt_status);
153 : }
154 311 : if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
155 0 : return ADS_ERROR_NT(nt_status);
156 : }
157 :
158 311 : if (server_blob.length == 0) {
159 1 : use_spnego_principal = false;
160 : }
161 :
162 311 : if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
163 1 : use_spnego_principal = false;
164 : }
165 :
166 311 : cli_credentials_set_kerberos_state(auth_generic_state->credentials,
167 : krb5_state,
168 : CRED_SPECIFIED);
169 :
170 311 : if (target_service != NULL) {
171 311 : nt_status = gensec_set_target_service(
172 311 : auth_generic_state->gensec_security,
173 : target_service);
174 311 : if (!NT_STATUS_IS_OK(nt_status)) {
175 0 : return ADS_ERROR_NT(nt_status);
176 : }
177 : }
178 :
179 311 : if (target_hostname != NULL) {
180 311 : nt_status = gensec_set_target_hostname(
181 311 : auth_generic_state->gensec_security,
182 : target_hostname);
183 311 : if (!NT_STATUS_IS_OK(nt_status)) {
184 0 : return ADS_ERROR_NT(nt_status);
185 : }
186 : }
187 :
188 311 : if (target_service != NULL && target_hostname != NULL) {
189 311 : use_spnego_principal = false;
190 : }
191 :
192 311 : switch (wrap->wrap_type) {
193 311 : case ADS_SASLWRAP_TYPE_SEAL:
194 311 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
195 311 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
196 311 : break;
197 0 : case ADS_SASLWRAP_TYPE_SIGN:
198 0 : if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
199 0 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
200 : } else {
201 : /*
202 : * windows servers are broken with sign only,
203 : * so we let the NTLMSSP backend to seal here,
204 : * via GENSEC_FEATURE_LDAP_STYLE.
205 : */
206 0 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
207 0 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
208 : }
209 0 : break;
210 0 : case ADS_SASLWRAP_TYPE_PLAIN:
211 0 : break;
212 : }
213 :
214 311 : nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
215 : sasl_list);
216 311 : if (!NT_STATUS_IS_OK(nt_status)) {
217 0 : return ADS_ERROR_NT(nt_status);
218 : }
219 :
220 311 : rc = LDAP_SASL_BIND_IN_PROGRESS;
221 311 : if (use_spnego_principal) {
222 0 : blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
223 0 : if (blob_in.length == 0) {
224 0 : TALLOC_FREE(auth_generic_state);
225 0 : return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
226 : }
227 : } else {
228 311 : blob_in = data_blob_null;
229 : }
230 311 : blob_out = data_blob_null;
231 :
232 308 : while (true) {
233 619 : struct berval cred, *scred = NULL;
234 :
235 619 : nt_status = gensec_update(auth_generic_state->gensec_security,
236 : talloc_tos(), blob_in, &blob_out);
237 619 : data_blob_free(&blob_in);
238 619 : if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
239 311 : && !NT_STATUS_IS_OK(nt_status))
240 : {
241 4 : TALLOC_FREE(auth_generic_state);
242 4 : data_blob_free(&blob_out);
243 4 : return ADS_ERROR_NT(nt_status);
244 : }
245 :
246 615 : if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
247 307 : break;
248 : }
249 :
250 308 : cred.bv_val = (char *)blob_out.data;
251 308 : cred.bv_len = blob_out.length;
252 308 : scred = NULL;
253 308 : rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
254 308 : data_blob_free(&blob_out);
255 308 : if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
256 0 : if (scred) {
257 0 : ber_bvfree(scred);
258 : }
259 :
260 0 : TALLOC_FREE(auth_generic_state);
261 0 : return ADS_ERROR(rc);
262 : }
263 308 : if (scred) {
264 308 : blob_in = data_blob_talloc(talloc_tos(),
265 : scred->bv_val,
266 : scred->bv_len);
267 308 : if (blob_in.length != scred->bv_len) {
268 0 : ber_bvfree(scred);
269 0 : TALLOC_FREE(auth_generic_state);
270 0 : return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
271 : }
272 308 : ber_bvfree(scred);
273 : } else {
274 0 : blob_in = data_blob_null;
275 : }
276 308 : if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
277 0 : break;
278 : }
279 : }
280 :
281 307 : data_blob_free(&blob_in);
282 307 : data_blob_free(&blob_out);
283 :
284 307 : if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
285 0 : bool ok;
286 :
287 307 : ok = gensec_have_feature(auth_generic_state->gensec_security,
288 : GENSEC_FEATURE_SEAL);
289 307 : if (!ok) {
290 0 : DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
291 0 : TALLOC_FREE(auth_generic_state);
292 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
293 : }
294 :
295 307 : ok = gensec_have_feature(auth_generic_state->gensec_security,
296 : GENSEC_FEATURE_SIGN);
297 307 : if (!ok) {
298 0 : DEBUG(0,("The gensec feature signing request, but unavailable\n"));
299 0 : TALLOC_FREE(auth_generic_state);
300 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
301 : }
302 :
303 0 : } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
304 0 : bool ok;
305 :
306 0 : ok = gensec_have_feature(auth_generic_state->gensec_security,
307 : GENSEC_FEATURE_SIGN);
308 0 : if (!ok) {
309 0 : DEBUG(0,("The gensec feature signing request, but unavailable\n"));
310 0 : TALLOC_FREE(auth_generic_state);
311 0 : return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
312 : }
313 : }
314 :
315 307 : ads->auth.tgs_expire = LONG_MAX;
316 307 : end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
317 307 : if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
318 0 : struct timeval tv;
319 306 : nttime_to_timeval(&tv, end_nt_time);
320 306 : ads->auth.tgs_expire = tv.tv_sec;
321 : }
322 :
323 307 : if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
324 0 : size_t max_wrapped =
325 307 : gensec_max_wrapped_size(auth_generic_state->gensec_security);
326 307 : wrap->out.max_unwrapped =
327 307 : gensec_max_input_size(auth_generic_state->gensec_security);
328 :
329 307 : wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
330 : /*
331 : * Note that we have to truncate this to 0x2C
332 : * (taken from a capture with LDAP unbind), as the
333 : * signature size is not constant for Kerberos with
334 : * arcfour-hmac-md5.
335 : */
336 307 : wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
337 307 : wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
338 307 : status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
339 : &ads_sasl_gensec_ops,
340 307 : auth_generic_state->gensec_security);
341 307 : if (!ADS_ERR_OK(status)) {
342 0 : DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
343 : ads_errstr(status)));
344 0 : TALLOC_FREE(auth_generic_state);
345 0 : return status;
346 : }
347 : /* Only keep the gensec_security element around long-term */
348 307 : talloc_steal(NULL, auth_generic_state->gensec_security);
349 : }
350 307 : TALLOC_FREE(auth_generic_state);
351 :
352 307 : return ADS_ERROR(rc);
353 : }
354 :
355 : #ifdef HAVE_KRB5
356 : struct ads_service_principal {
357 : char *service;
358 : char *hostname;
359 : char *string;
360 : };
361 :
362 312 : static void ads_free_service_principal(struct ads_service_principal *p)
363 : {
364 312 : SAFE_FREE(p->service);
365 312 : SAFE_FREE(p->hostname);
366 312 : SAFE_FREE(p->string);
367 312 : ZERO_STRUCTP(p);
368 312 : }
369 :
370 312 : static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
371 : char **service,
372 : char **hostname,
373 : char **principal)
374 : {
375 312 : ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
376 312 : char *princ = NULL;
377 0 : TALLOC_CTX *frame;
378 312 : char *server = NULL;
379 312 : char *realm = NULL;
380 0 : int rc;
381 :
382 312 : frame = talloc_stackframe();
383 312 : if (frame == NULL) {
384 0 : return ADS_ERROR(LDAP_NO_MEMORY);
385 : }
386 :
387 312 : if (ads->server.realm && ads->server.ldap_server) {
388 150 : server = strlower_talloc(frame, ads->server.ldap_server);
389 150 : if (server == NULL) {
390 0 : goto out;
391 : }
392 :
393 150 : realm = strupper_talloc(frame, ads->server.realm);
394 150 : if (realm == NULL) {
395 0 : goto out;
396 : }
397 :
398 : /*
399 : * If we got a name which is bigger than a NetBIOS name,
400 : * but isn't a FQDN, create one.
401 : */
402 150 : if (strlen(server) > 15 && strstr(server, ".") == NULL) {
403 0 : char *dnsdomain;
404 :
405 0 : dnsdomain = strlower_talloc(frame, ads->server.realm);
406 0 : if (dnsdomain == NULL) {
407 0 : goto out;
408 : }
409 :
410 0 : server = talloc_asprintf(frame,
411 : "%s.%s",
412 : server, dnsdomain);
413 0 : if (server == NULL) {
414 0 : goto out;
415 : }
416 : }
417 162 : } else if (ads->config.realm && ads->config.ldap_server_name) {
418 162 : server = strlower_talloc(frame, ads->config.ldap_server_name);
419 162 : if (server == NULL) {
420 0 : goto out;
421 : }
422 :
423 162 : realm = strupper_talloc(frame, ads->config.realm);
424 162 : if (realm == NULL) {
425 0 : goto out;
426 : }
427 :
428 : /*
429 : * If we got a name which is bigger than a NetBIOS name,
430 : * but isn't a FQDN, create one.
431 : */
432 162 : if (strlen(server) > 15 && strstr(server, ".") == NULL) {
433 0 : char *dnsdomain;
434 :
435 0 : dnsdomain = strlower_talloc(frame, ads->server.realm);
436 0 : if (dnsdomain == NULL) {
437 0 : goto out;
438 : }
439 :
440 0 : server = talloc_asprintf(frame,
441 : "%s.%s",
442 : server, dnsdomain);
443 0 : if (server == NULL) {
444 0 : goto out;
445 : }
446 : }
447 : }
448 :
449 312 : if (server == NULL || realm == NULL) {
450 0 : goto out;
451 : }
452 :
453 312 : *service = SMB_STRDUP("ldap");
454 312 : if (*service == NULL) {
455 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
456 0 : goto out;
457 : }
458 312 : *hostname = SMB_STRDUP(server);
459 312 : if (*hostname == NULL) {
460 0 : SAFE_FREE(*service);
461 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
462 0 : goto out;
463 : }
464 312 : rc = asprintf(&princ, "ldap/%s@%s", server, realm);
465 312 : if (rc == -1 || princ == NULL) {
466 0 : SAFE_FREE(*service);
467 0 : SAFE_FREE(*hostname);
468 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
469 0 : goto out;
470 : }
471 :
472 312 : *principal = princ;
473 :
474 312 : status = ADS_SUCCESS;
475 312 : out:
476 312 : TALLOC_FREE(frame);
477 312 : return status;
478 : }
479 :
480 312 : static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
481 : struct ads_service_principal *p)
482 : {
483 0 : ADS_STATUS status;
484 :
485 312 : ZERO_STRUCTP(p);
486 :
487 312 : status = ads_guess_target(ads,
488 : &p->service,
489 : &p->hostname,
490 : &p->string);
491 312 : if (!ADS_ERR_OK(status)) {
492 0 : return status;
493 : }
494 :
495 312 : return ADS_SUCCESS;
496 : }
497 :
498 : #endif /* HAVE_KRB5 */
499 :
500 : /*
501 : parse a negTokenInit packet giving a GUID, a list of supported
502 : OIDs (the mechanisms) and a principal name string
503 : */
504 312 : static bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
505 : DATA_BLOB blob,
506 : char *OIDs[ASN1_MAX_OIDS],
507 : char **principal,
508 : DATA_BLOB *secblob)
509 : {
510 0 : int i;
511 312 : bool ret = false;
512 0 : ASN1_DATA *data;
513 :
514 6552 : for (i = 0; i < ASN1_MAX_OIDS; i++) {
515 6240 : OIDs[i] = NULL;
516 : }
517 :
518 312 : if (principal) {
519 312 : *principal = NULL;
520 : }
521 312 : if (secblob) {
522 0 : *secblob = data_blob_null;
523 : }
524 :
525 312 : data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
526 312 : if (data == NULL) {
527 0 : return false;
528 : }
529 :
530 312 : if (!asn1_load(data, blob)) goto err;
531 :
532 312 : if (!asn1_start_tag(data,ASN1_APPLICATION(0))) goto err;
533 :
534 312 : if (!asn1_check_OID(data,OID_SPNEGO)) goto err;
535 :
536 : /* negTokenInit [0] NegTokenInit */
537 312 : if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
538 312 : if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
539 :
540 : /* mechTypes [0] MechTypeList OPTIONAL */
541 :
542 : /* Not really optional, we depend on this to decide
543 : * what mechanisms we have to work with. */
544 :
545 312 : if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
546 312 : if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
547 1248 : for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
548 936 : if (!asn1_read_OID(data,ctx, &OIDs[i])) {
549 0 : goto err;
550 : }
551 936 : if (asn1_has_error(data)) {
552 0 : goto err;
553 : }
554 : }
555 312 : OIDs[i] = NULL;
556 312 : if (!asn1_end_tag(data)) goto err;
557 312 : if (!asn1_end_tag(data)) goto err;
558 :
559 : /*
560 : Win7 + Live Sign-in Assistant attaches a mechToken
561 : ASN1_CONTEXT(2) to the negTokenInit packet
562 : which breaks our negotiation if we just assume
563 : the next tag is ASN1_CONTEXT(3).
564 : */
565 :
566 312 : if (asn1_peek_tag(data, ASN1_CONTEXT(1))) {
567 0 : uint8_t flags;
568 :
569 : /* reqFlags [1] ContextFlags OPTIONAL */
570 0 : if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err;
571 0 : if (!asn1_start_tag(data, ASN1_BIT_STRING)) goto err;
572 0 : while (asn1_tag_remaining(data) > 0) {
573 0 : if (!asn1_read_uint8(data, &flags)) goto err;
574 : }
575 0 : if (!asn1_end_tag(data)) goto err;
576 0 : if (!asn1_end_tag(data)) goto err;
577 : }
578 :
579 312 : if (asn1_peek_tag(data, ASN1_CONTEXT(2))) {
580 0 : DATA_BLOB sblob = data_blob_null;
581 : /* mechToken [2] OCTET STRING OPTIONAL */
582 0 : if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err;
583 0 : if (!asn1_read_OctetString(data, ctx, &sblob)) goto err;
584 0 : if (!asn1_end_tag(data)) {
585 0 : data_blob_free(&sblob);
586 0 : goto err;
587 : }
588 0 : if (secblob) {
589 0 : *secblob = sblob;
590 : } else {
591 0 : data_blob_free(&sblob);
592 : }
593 : }
594 :
595 312 : if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
596 312 : char *princ = NULL;
597 : /* mechListMIC [3] OCTET STRING OPTIONAL */
598 312 : if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err;
599 312 : if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err;
600 312 : if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err;
601 312 : if (!asn1_read_GeneralString(data, ctx, &princ)) goto err;
602 312 : if (!asn1_end_tag(data)) goto err;
603 312 : if (!asn1_end_tag(data)) goto err;
604 312 : if (!asn1_end_tag(data)) goto err;
605 312 : if (principal) {
606 312 : *principal = princ;
607 : } else {
608 0 : TALLOC_FREE(princ);
609 : }
610 : }
611 :
612 312 : if (!asn1_end_tag(data)) goto err;
613 312 : if (!asn1_end_tag(data)) goto err;
614 :
615 312 : if (!asn1_end_tag(data)) goto err;
616 :
617 312 : ret = !asn1_has_error(data);
618 :
619 312 : err:
620 :
621 312 : if (asn1_has_error(data)) {
622 0 : int j;
623 0 : if (principal) {
624 0 : TALLOC_FREE(*principal);
625 : }
626 0 : if (secblob) {
627 0 : data_blob_free(secblob);
628 : }
629 0 : for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
630 0 : TALLOC_FREE(OIDs[j]);
631 : }
632 : }
633 :
634 312 : asn1_free(data);
635 312 : return ret;
636 : }
637 :
638 : /*
639 : this performs a SASL/SPNEGO bind
640 : */
641 312 : static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
642 : {
643 312 : TALLOC_CTX *frame = talloc_stackframe();
644 312 : struct ads_service_principal p = {0};
645 312 : struct berval *scred=NULL;
646 0 : int rc, i;
647 0 : ADS_STATUS status;
648 312 : DATA_BLOB blob = data_blob_null;
649 312 : char *given_principal = NULL;
650 0 : char *OIDs[ASN1_MAX_OIDS];
651 : #ifdef HAVE_KRB5
652 312 : bool got_kerberos_mechanism = False;
653 : #endif
654 312 : const char *mech = NULL;
655 :
656 312 : rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
657 :
658 312 : if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
659 0 : status = ADS_ERROR(rc);
660 0 : goto done;
661 : }
662 :
663 312 : blob = data_blob(scred->bv_val, scred->bv_len);
664 :
665 312 : ber_bvfree(scred);
666 :
667 : #if 0
668 : file_save("sasl_spnego.dat", blob.data, blob.length);
669 : #endif
670 :
671 : /* the server sent us the first part of the SPNEGO exchange in the negprot
672 : reply */
673 312 : if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
674 312 : OIDs[0] == NULL) {
675 0 : status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
676 0 : goto done;
677 : }
678 312 : TALLOC_FREE(given_principal);
679 :
680 : /* make sure the server understands kerberos */
681 1248 : for (i=0;OIDs[i];i++) {
682 936 : DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
683 : #ifdef HAVE_KRB5
684 936 : if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
685 624 : strcmp(OIDs[i], OID_KERBEROS5) == 0) {
686 624 : got_kerberos_mechanism = True;
687 : }
688 : #endif
689 936 : talloc_free(OIDs[i]);
690 : }
691 :
692 312 : status = ads_generate_service_principal(ads, &p);
693 312 : if (!ADS_ERR_OK(status)) {
694 0 : goto done;
695 : }
696 :
697 : #ifdef HAVE_KRB5
698 312 : if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
699 : got_kerberos_mechanism)
700 : {
701 310 : mech = "KRB5";
702 :
703 310 : if (ads->auth.password == NULL ||
704 306 : ads->auth.password[0] == '\0')
705 : {
706 :
707 4 : status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
708 : CRED_USE_KERBEROS_REQUIRED,
709 4 : p.service, p.hostname,
710 : blob);
711 4 : if (ADS_ERR_OK(status)) {
712 0 : ads_free_service_principal(&p);
713 0 : goto done;
714 : }
715 :
716 4 : DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
717 : "calling kinit\n", ads_errstr(status)));
718 : }
719 :
720 310 : status = ADS_ERROR_KRB5(ads_kinit_password(ads));
721 :
722 310 : if (ADS_ERR_OK(status)) {
723 306 : status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
724 : CRED_USE_KERBEROS_REQUIRED,
725 306 : p.service, p.hostname,
726 : blob);
727 306 : if (!ADS_ERR_OK(status)) {
728 0 : DBG_ERR("kinit succeeded but "
729 : "SPNEGO bind with Kerberos failed "
730 : "for %s/%s - user[%s], realm[%s]: %s\n",
731 : p.service, p.hostname,
732 : ads->auth.user_name,
733 : ads->auth.realm,
734 : ads_errstr(status));
735 : }
736 : }
737 :
738 : /* only fallback to NTLMSSP if allowed */
739 310 : if (ADS_ERR_OK(status) ||
740 4 : !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
741 310 : goto done;
742 : }
743 :
744 0 : DBG_WARNING("SASL bind with Kerberos failed "
745 : "for %s/%s - user[%s], realm[%s]: %s, "
746 : "try to fallback to NTLMSSP\n",
747 : p.service, p.hostname,
748 : ads->auth.user_name,
749 : ads->auth.realm,
750 : ads_errstr(status));
751 : }
752 : #endif
753 :
754 : /* lets do NTLMSSP ... this has the big advantage that we don't need
755 : to sync clocks, and we don't rely on special versions of the krb5
756 : library for HMAC_MD4 encryption */
757 2 : mech = "NTLMSSP";
758 :
759 2 : if (!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
760 0 : DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
761 0 : status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
762 0 : goto done;
763 : }
764 :
765 2 : if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
766 1 : DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
767 : " disallowed.\n");
768 1 : status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
769 1 : goto done;
770 : }
771 :
772 1 : status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
773 : CRED_USE_KERBEROS_DISABLED,
774 1 : p.service, p.hostname,
775 : data_blob_null);
776 312 : done:
777 312 : if (!ADS_ERR_OK(status)) {
778 5 : DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
779 : "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
780 : p.service, p.hostname,
781 : ads->auth.user_name,
782 : ads->auth.realm,
783 : ads_errstr(status)));
784 : }
785 312 : ads_free_service_principal(&p);
786 312 : TALLOC_FREE(frame);
787 312 : if (blob.data != NULL) {
788 312 : data_blob_free(&blob);
789 : }
790 312 : return status;
791 : }
792 :
793 : /* mapping between SASL mechanisms and functions */
794 : static struct {
795 : const char *name;
796 : ADS_STATUS (*fn)(ADS_STRUCT *);
797 : } sasl_mechanisms[] = {
798 : {"GSS-SPNEGO", ads_sasl_spnego_bind},
799 : {NULL, NULL}
800 : };
801 :
802 312 : ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
803 : {
804 312 : const char *attrs[] = {"supportedSASLMechanisms", NULL};
805 0 : char **values;
806 0 : ADS_STATUS status;
807 0 : int i, j;
808 0 : LDAPMessage *res;
809 312 : struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
810 :
811 : /* get a list of supported SASL mechanisms */
812 312 : status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
813 312 : if (!ADS_ERR_OK(status)) return status;
814 :
815 312 : values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
816 :
817 312 : if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
818 312 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
819 0 : } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
820 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
821 : } else {
822 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
823 : }
824 :
825 : /* try our supported mechanisms in order */
826 312 : for (i=0;sasl_mechanisms[i].name;i++) {
827 : /* see if the server supports it */
828 312 : for (j=0;values && values[j];j++) {
829 312 : if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
830 312 : DEBUG(4,("Found SASL mechanism %s\n", values[j]));
831 312 : retry:
832 312 : status = sasl_mechanisms[i].fn(ads);
833 312 : if (status.error_type == ENUM_ADS_ERROR_LDAP &&
834 307 : status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
835 0 : wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
836 : {
837 0 : DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
838 : "retrying with signing enabled\n"));
839 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
840 0 : goto retry;
841 : }
842 312 : ldap_value_free(values);
843 312 : ldap_msgfree(res);
844 312 : return status;
845 : }
846 : }
847 : }
848 :
849 0 : ldap_value_free(values);
850 0 : ldap_msgfree(res);
851 0 : return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
852 : }
853 :
854 : #endif /* HAVE_LDAP */
855 :
|