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