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 1758 : static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
34 : uint8_t *buf, uint32_t len)
35 : {
36 909 : struct gensec_security *gensec_security =
37 1758 : talloc_get_type_abort(wrap->wrap_private_data,
38 : struct gensec_security);
39 : NTSTATUS nt_status;
40 : DATA_BLOB unwrapped, wrapped;
41 1758 : TALLOC_CTX *frame = talloc_stackframe();
42 :
43 1758 : unwrapped = data_blob_const(buf, len);
44 :
45 1758 : nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
46 1758 : if (!NT_STATUS_IS_OK(nt_status)) {
47 0 : TALLOC_FREE(frame);
48 0 : return ADS_ERROR_NT(nt_status);
49 : }
50 :
51 1758 : 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 1758 : memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
58 :
59 : /* set how many bytes must be written to the underlying socket */
60 1758 : wrap->out.left = 4 + wrapped.length;
61 :
62 1758 : TALLOC_FREE(frame);
63 :
64 1758 : return ADS_SUCCESS;
65 : }
66 :
67 1488 : static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
68 : {
69 768 : struct gensec_security *gensec_security =
70 1488 : talloc_get_type_abort(wrap->wrap_private_data,
71 : struct gensec_security);
72 : NTSTATUS nt_status;
73 : DATA_BLOB unwrapped, wrapped;
74 1488 : TALLOC_CTX *frame = talloc_stackframe();
75 :
76 1488 : wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
77 :
78 1488 : nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
79 1488 : if (!NT_STATUS_IS_OK(nt_status)) {
80 0 : TALLOC_FREE(frame);
81 0 : return ADS_ERROR_NT(nt_status);
82 : }
83 :
84 1488 : 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 1488 : memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
91 :
92 : /* set how many bytes must be written to the underlying socket */
93 1488 : wrap->in.left = unwrapped.length;
94 1488 : wrap->in.ofs = 4;
95 :
96 1488 : TALLOC_FREE(frame);
97 :
98 1488 : return ADS_SUCCESS;
99 : }
100 :
101 270 : static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
102 : {
103 141 : struct gensec_security *gensec_security =
104 270 : talloc_get_type_abort(wrap->wrap_private_data,
105 : struct gensec_security);
106 :
107 270 : TALLOC_FREE(gensec_security);
108 :
109 270 : wrap->wrap_ops = NULL;
110 270 : wrap->wrap_private_data = NULL;
111 270 : }
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 342 : 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 342 : DATA_BLOB blob_in = data_blob_null;
132 342 : 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 342 : bool use_spnego_principal = lp_client_use_spnego_principal();
138 342 : const char *sasl_list[] = { sasl, NULL };
139 : NTTIME end_nt_time;
140 342 : struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
141 :
142 342 : nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
143 342 : if (!NT_STATUS_IS_OK(nt_status)) {
144 0 : return ADS_ERROR_NT(nt_status);
145 : }
146 :
147 342 : 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 342 : 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 342 : 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 342 : if (server_blob.length == 0) {
158 0 : use_spnego_principal = false;
159 : }
160 :
161 342 : if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
162 0 : use_spnego_principal = false;
163 : }
164 :
165 342 : cli_credentials_set_kerberos_state(auth_generic_state->credentials,
166 : krb5_state,
167 : CRED_SPECIFIED);
168 :
169 342 : if (target_service != NULL) {
170 342 : nt_status = gensec_set_target_service(
171 342 : auth_generic_state->gensec_security,
172 : target_service);
173 342 : if (!NT_STATUS_IS_OK(nt_status)) {
174 0 : return ADS_ERROR_NT(nt_status);
175 : }
176 : }
177 :
178 342 : if (target_hostname != NULL) {
179 342 : nt_status = gensec_set_target_hostname(
180 342 : auth_generic_state->gensec_security,
181 : target_hostname);
182 342 : if (!NT_STATUS_IS_OK(nt_status)) {
183 0 : return ADS_ERROR_NT(nt_status);
184 : }
185 : }
186 :
187 342 : if (target_service != NULL && target_hostname != NULL) {
188 342 : use_spnego_principal = false;
189 : }
190 :
191 342 : switch (wrap->wrap_type) {
192 104 : case ADS_SASLWRAP_TYPE_SEAL:
193 104 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
194 104 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
195 104 : break;
196 238 : case ADS_SASLWRAP_TYPE_SIGN:
197 238 : 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 238 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
206 238 : gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
207 : }
208 238 : break;
209 0 : case ADS_SASLWRAP_TYPE_PLAIN:
210 0 : break;
211 : }
212 :
213 342 : nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
214 : sasl_list);
215 342 : if (!NT_STATUS_IS_OK(nt_status)) {
216 0 : return ADS_ERROR_NT(nt_status);
217 : }
218 :
219 342 : rc = LDAP_SASL_BIND_IN_PROGRESS;
220 342 : 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 342 : blob_in = data_blob_null;
228 : }
229 342 : blob_out = data_blob_null;
230 :
231 340 : while (true) {
232 682 : struct berval cred, *scred = NULL;
233 :
234 682 : nt_status = gensec_update(auth_generic_state->gensec_security,
235 : talloc_tos(), blob_in, &blob_out);
236 682 : data_blob_free(&blob_in);
237 682 : if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
238 342 : && !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 680 : if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
246 516 : break;
247 : }
248 :
249 340 : cred.bv_val = (char *)blob_out.data;
250 340 : cred.bv_len = blob_out.length;
251 340 : scred = NULL;
252 340 : rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
253 340 : data_blob_free(&blob_out);
254 340 : 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 340 : if (scred) {
263 340 : blob_in = data_blob_talloc(talloc_tos(),
264 : scred->bv_val,
265 : scred->bv_len);
266 340 : 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 340 : ber_bvfree(scred);
272 : } else {
273 0 : blob_in = data_blob_null;
274 : }
275 340 : if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
276 0 : break;
277 : }
278 : }
279 :
280 340 : data_blob_free(&blob_in);
281 340 : data_blob_free(&blob_out);
282 :
283 340 : if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
284 : bool ok;
285 :
286 104 : ok = gensec_have_feature(auth_generic_state->gensec_security,
287 : GENSEC_FEATURE_SEAL);
288 104 : 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 104 : ok = gensec_have_feature(auth_generic_state->gensec_security,
295 : GENSEC_FEATURE_SIGN);
296 104 : 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 236 : } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
303 : bool ok;
304 :
305 236 : ok = gensec_have_feature(auth_generic_state->gensec_security,
306 : GENSEC_FEATURE_SIGN);
307 236 : 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 340 : ads->auth.tgs_expire = LONG_MAX;
315 340 : end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
316 340 : if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
317 : struct timeval tv;
318 340 : nttime_to_timeval(&tv, end_nt_time);
319 340 : ads->auth.tgs_expire = tv.tv_sec;
320 : }
321 :
322 340 : if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
323 176 : size_t max_wrapped =
324 340 : gensec_max_wrapped_size(auth_generic_state->gensec_security);
325 340 : wrap->out.max_unwrapped =
326 340 : gensec_max_input_size(auth_generic_state->gensec_security);
327 :
328 340 : 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 340 : wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
336 340 : wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
337 340 : status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
338 : &ads_sasl_gensec_ops,
339 340 : auth_generic_state->gensec_security);
340 340 : 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 340 : talloc_steal(NULL, auth_generic_state->gensec_security);
348 : }
349 340 : TALLOC_FREE(auth_generic_state);
350 :
351 340 : 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 342 : static void ads_free_service_principal(struct ads_service_principal *p)
362 : {
363 342 : SAFE_FREE(p->service);
364 342 : SAFE_FREE(p->hostname);
365 342 : SAFE_FREE(p->string);
366 342 : ZERO_STRUCTP(p);
367 342 : }
368 :
369 342 : static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
370 : char **service,
371 : char **hostname,
372 : char **principal)
373 : {
374 342 : ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
375 342 : char *princ = NULL;
376 : TALLOC_CTX *frame;
377 342 : char *server = NULL;
378 342 : char *realm = NULL;
379 : int rc;
380 :
381 342 : frame = talloc_stackframe();
382 342 : if (frame == NULL) {
383 0 : return ADS_ERROR(LDAP_NO_MEMORY);
384 : }
385 :
386 342 : if (ads->server.realm && ads->server.ldap_server) {
387 166 : server = strlower_talloc(frame, ads->server.ldap_server);
388 166 : if (server == NULL) {
389 0 : goto out;
390 : }
391 :
392 166 : realm = strupper_talloc(frame, ads->server.realm);
393 166 : 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 253 : 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 176 : } else if (ads->config.realm && ads->config.ldap_server_name) {
417 176 : server = strlower_talloc(frame, ads->config.ldap_server_name);
418 176 : if (server == NULL) {
419 0 : goto out;
420 : }
421 :
422 176 : realm = strupper_talloc(frame, ads->config.realm);
423 176 : 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 176 : 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 520 : if (server == NULL || realm == NULL) {
449 0 : goto out;
450 : }
451 :
452 342 : *service = SMB_STRDUP("ldap");
453 342 : if (*service == NULL) {
454 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
455 0 : goto out;
456 : }
457 342 : *hostname = SMB_STRDUP(server);
458 342 : if (*hostname == NULL) {
459 0 : SAFE_FREE(*service);
460 0 : status = ADS_ERROR(LDAP_PARAM_ERROR);
461 0 : goto out;
462 : }
463 342 : rc = asprintf(&princ, "ldap/%s@%s", server, realm);
464 342 : 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 342 : *principal = princ;
472 :
473 342 : status = ADS_SUCCESS;
474 342 : out:
475 342 : TALLOC_FREE(frame);
476 342 : return status;
477 : }
478 :
479 342 : static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
480 : struct ads_service_principal *p)
481 : {
482 : ADS_STATUS status;
483 :
484 342 : ZERO_STRUCTP(p);
485 :
486 342 : status = ads_guess_target(ads,
487 : &p->service,
488 : &p->hostname,
489 : &p->string);
490 342 : if (!ADS_ERR_OK(status)) {
491 0 : return status;
492 : }
493 :
494 342 : return ADS_SUCCESS;
495 : }
496 :
497 : #endif /* HAVE_KRB5 */
498 :
499 : /*
500 : this performs a SASL/SPNEGO bind
501 : */
502 342 : static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
503 : {
504 342 : TALLOC_CTX *frame = talloc_stackframe();
505 342 : struct ads_service_principal p = {0};
506 342 : struct berval *scred=NULL;
507 : int rc, i;
508 : ADS_STATUS status;
509 342 : DATA_BLOB blob = data_blob_null;
510 342 : char *given_principal = NULL;
511 : char *OIDs[ASN1_MAX_OIDS];
512 : #ifdef HAVE_KRB5
513 342 : bool got_kerberos_mechanism = False;
514 : #endif
515 342 : const char *mech = NULL;
516 :
517 342 : rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
518 :
519 342 : if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
520 0 : status = ADS_ERROR(rc);
521 0 : goto done;
522 : }
523 :
524 342 : blob = data_blob(scred->bv_val, scred->bv_len);
525 :
526 342 : 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 520 : if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
535 342 : OIDs[0] == NULL) {
536 0 : status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
537 0 : goto done;
538 : }
539 342 : TALLOC_FREE(given_principal);
540 :
541 : /* make sure the server understands kerberos */
542 1368 : for (i=0;OIDs[i];i++) {
543 1026 : DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
544 : #ifdef HAVE_KRB5
545 1382 : if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
546 684 : strcmp(OIDs[i], OID_KERBEROS5) == 0) {
547 684 : got_kerberos_mechanism = True;
548 : }
549 : #endif
550 1026 : talloc_free(OIDs[i]);
551 : }
552 :
553 342 : status = ads_generate_service_principal(ads, &p);
554 342 : if (!ADS_ERR_OK(status)) {
555 0 : goto done;
556 : }
557 :
558 : #ifdef HAVE_KRB5
559 342 : if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
560 : got_kerberos_mechanism)
561 : {
562 342 : mech = "KRB5";
563 :
564 518 : if (ads->auth.password == NULL ||
565 340 : 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 342 : status = ADS_ERROR_KRB5(ads_kinit_password(ads));
582 :
583 342 : if (ADS_ERR_OK(status)) {
584 340 : status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
585 : CRED_USE_KERBEROS_REQUIRED,
586 340 : p.service, p.hostname,
587 : blob);
588 340 : if (!ADS_ERR_OK(status)) {
589 0 : DEBUG(0,("kinit succeeded but "
590 : "ads_sasl_spnego_gensec_bind(KRB5) failed "
591 : "for %s/%s with 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 522 : if (ADS_ERR_OK(status) ||
601 2 : !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
602 164 : goto done;
603 : }
604 :
605 0 : DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
606 : "for %s/%s with user[%s] realm[%s]: %s, "
607 : "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 0 : mech = "NTLMSSP";
619 0 : status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
620 : CRED_USE_KERBEROS_DISABLED,
621 0 : p.service, p.hostname,
622 : data_blob_null);
623 520 : done:
624 342 : if (!ADS_ERR_OK(status)) {
625 2 : DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
626 : "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
627 : p.service, p.hostname,
628 : ads->auth.user_name,
629 : ads->auth.realm,
630 : ads_errstr(status)));
631 : }
632 342 : ads_free_service_principal(&p);
633 342 : TALLOC_FREE(frame);
634 342 : if (blob.data != NULL) {
635 342 : data_blob_free(&blob);
636 : }
637 342 : return status;
638 : }
639 :
640 : /* mapping between SASL mechanisms and functions */
641 : static struct {
642 : const char *name;
643 : ADS_STATUS (*fn)(ADS_STRUCT *);
644 : } sasl_mechanisms[] = {
645 : {"GSS-SPNEGO", ads_sasl_spnego_bind},
646 : {NULL, NULL}
647 : };
648 :
649 342 : ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
650 : {
651 342 : const char *attrs[] = {"supportedSASLMechanisms", NULL};
652 : char **values;
653 : ADS_STATUS status;
654 : int i, j;
655 : LDAPMessage *res;
656 342 : struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
657 :
658 : /* get a list of supported SASL mechanisms */
659 342 : status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
660 342 : if (!ADS_ERR_OK(status)) return status;
661 :
662 342 : values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
663 :
664 342 : if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
665 104 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
666 238 : } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
667 238 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
668 : } else {
669 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
670 : }
671 :
672 : /* try our supported mechanisms in order */
673 342 : for (i=0;sasl_mechanisms[i].name;i++) {
674 : /* see if the server supports it */
675 342 : for (j=0;values && values[j];j++) {
676 342 : if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
677 342 : DEBUG(4,("Found SASL mechanism %s\n", values[j]));
678 342 : retry:
679 342 : status = sasl_mechanisms[i].fn(ads);
680 518 : if (status.error_type == ENUM_ADS_ERROR_LDAP &&
681 340 : status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
682 0 : wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
683 : {
684 0 : DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
685 : "retrying with signing enabled\n"));
686 0 : wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
687 0 : goto retry;
688 : }
689 342 : ldap_value_free(values);
690 342 : ldap_msgfree(res);
691 342 : return status;
692 : }
693 : }
694 : }
695 :
696 0 : ldap_value_free(values);
697 0 : ldap_msgfree(res);
698 0 : return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
699 : }
700 :
701 : #endif /* HAVE_LDAP */
702 :
|