Introduce system MIT krb5 build with --with-system-mitkrb5 option.
[Samba.git] / source3 / libads / sasl.c
blob42d65b63d47e01307fcf5ca09cc96ff0eb0ab080
1 /*
2 Unix SMB/CIFS implementation.
3 ads sasl code
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "auth/gensec/gensec.h"
23 #include "auth_generic.h"
24 #include "ads.h"
25 #include "smb_krb5.h"
26 #include "system/gssapi.h"
28 #ifdef HAVE_LDAP
30 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
32 struct gensec_security *gensec_security =
33 talloc_get_type_abort(ads->ldap.wrap_private_data,
34 struct gensec_security);
35 NTSTATUS nt_status;
36 DATA_BLOB unwrapped, wrapped;
37 TALLOC_CTX *frame = talloc_stackframe();
39 unwrapped = data_blob_const(buf, len);
41 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
42 if (!NT_STATUS_IS_OK(nt_status)) {
43 TALLOC_FREE(frame);
44 return ADS_ERROR_NT(nt_status);
47 if ((ads->ldap.out.size - 4) < wrapped.length) {
48 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
51 /* copy the wrapped blob to the right location */
52 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
54 /* set how many bytes must be written to the underlying socket */
55 ads->ldap.out.left = 4 + wrapped.length;
57 TALLOC_FREE(frame);
59 return ADS_SUCCESS;
62 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
64 struct gensec_security *gensec_security =
65 talloc_get_type_abort(ads->ldap.wrap_private_data,
66 struct gensec_security);
67 NTSTATUS nt_status;
68 DATA_BLOB unwrapped, wrapped;
69 TALLOC_CTX *frame = talloc_stackframe();
71 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
73 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
74 if (!NT_STATUS_IS_OK(nt_status)) {
75 TALLOC_FREE(frame);
76 return ADS_ERROR_NT(nt_status);
79 if (wrapped.length < unwrapped.length) {
80 TALLOC_FREE(frame);
81 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
84 /* copy the wrapped blob to the right location */
85 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
87 /* set how many bytes must be written to the underlying socket */
88 ads->ldap.in.left = unwrapped.length;
89 ads->ldap.in.ofs = 4;
91 TALLOC_FREE(frame);
93 return ADS_SUCCESS;
96 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
98 struct gensec_security *gensec_security =
99 talloc_get_type_abort(ads->ldap.wrap_private_data,
100 struct gensec_security);
102 TALLOC_FREE(gensec_security);
104 ads->ldap.wrap_ops = NULL;
105 ads->ldap.wrap_private_data = NULL;
108 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
109 .name = "ntlmssp",
110 .wrap = ads_sasl_ntlmssp_wrap,
111 .unwrap = ads_sasl_ntlmssp_unwrap,
112 .disconnect = ads_sasl_ntlmssp_disconnect
116 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
117 we fit on one socket??)
119 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
121 DATA_BLOB msg1 = data_blob_null;
122 DATA_BLOB blob = data_blob_null;
123 DATA_BLOB blob_in = data_blob_null;
124 DATA_BLOB blob_out = data_blob_null;
125 struct berval cred, *scred = NULL;
126 int rc;
127 NTSTATUS nt_status;
128 ADS_STATUS status;
129 int turn = 1;
131 struct auth_generic_state *auth_generic_state;
133 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
134 if (!NT_STATUS_IS_OK(nt_status)) {
135 return ADS_ERROR_NT(nt_status);
138 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
139 return ADS_ERROR_NT(nt_status);
141 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
142 return ADS_ERROR_NT(nt_status);
144 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
145 return ADS_ERROR_NT(nt_status);
148 switch (ads->ldap.wrap_type) {
149 case ADS_SASLWRAP_TYPE_SEAL:
150 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
151 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
152 break;
153 case ADS_SASLWRAP_TYPE_SIGN:
154 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
155 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
156 } else {
158 * windows servers are broken with sign only,
159 * so we need to use seal here too
161 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
162 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
163 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
165 break;
166 case ADS_SASLWRAP_TYPE_PLAIN:
167 break;
170 nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
171 if (!NT_STATUS_IS_OK(nt_status)) {
172 return ADS_ERROR_NT(nt_status);
175 blob_in = data_blob_null;
177 do {
178 nt_status = gensec_update(auth_generic_state->gensec_security,
179 talloc_tos(), NULL, blob_in, &blob_out);
180 data_blob_free(&blob_in);
181 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
182 || NT_STATUS_IS_OK(nt_status))
183 && blob_out.length) {
184 if (turn == 1) {
185 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
186 /* and wrap it in a SPNEGO wrapper */
187 msg1 = spnego_gen_negTokenInit(talloc_tos(),
188 OIDs_ntlm, &blob_out, NULL);
189 } else {
190 /* wrap it in SPNEGO */
191 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
194 data_blob_free(&blob_out);
196 cred.bv_val = (char *)msg1.data;
197 cred.bv_len = msg1.length;
198 scred = NULL;
199 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
200 data_blob_free(&msg1);
201 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
202 if (scred) {
203 ber_bvfree(scred);
206 TALLOC_FREE(auth_generic_state);
207 return ADS_ERROR(rc);
209 if (scred) {
210 blob = data_blob(scred->bv_val, scred->bv_len);
211 ber_bvfree(scred);
212 } else {
213 blob = data_blob_null;
216 } else {
218 TALLOC_FREE(auth_generic_state);
219 data_blob_free(&blob_out);
220 return ADS_ERROR_NT(nt_status);
223 if ((turn == 1) &&
224 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
225 DATA_BLOB tmp_blob = data_blob_null;
226 /* the server might give us back two challenges */
227 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
228 &tmp_blob)) {
230 TALLOC_FREE(auth_generic_state);
231 data_blob_free(&blob);
232 DEBUG(3,("Failed to parse challenges\n"));
233 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
235 data_blob_free(&tmp_blob);
236 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
237 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
238 &blob_in)) {
240 TALLOC_FREE(auth_generic_state);
241 data_blob_free(&blob);
242 DEBUG(3,("Failed to parse auth response\n"));
243 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
246 data_blob_free(&blob);
247 data_blob_free(&blob_out);
248 turn++;
249 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
251 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
252 uint32_t sig_size = gensec_sig_size(auth_generic_state->gensec_security, 0);
253 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - sig_size;
254 ads->ldap.out.sig_size = sig_size;
255 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
256 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
257 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
258 if (!ADS_ERR_OK(status)) {
259 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
260 ads_errstr(status)));
261 TALLOC_FREE(auth_generic_state);
262 return status;
264 /* Only keep the gensec_security element around long-term */
265 talloc_steal(NULL, auth_generic_state->gensec_security);
267 TALLOC_FREE(auth_generic_state);
269 return ADS_ERROR(rc);
272 #ifdef HAVE_KRB5
273 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
275 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
276 ADS_STATUS status;
277 int gss_rc;
278 uint32 minor_status;
279 gss_buffer_desc unwrapped, wrapped;
280 int conf_req_flag, conf_state;
282 unwrapped.value = buf;
283 unwrapped.length = len;
285 /* for now request sign and seal */
286 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
288 gss_rc = gss_wrap(&minor_status, context_handle,
289 conf_req_flag, GSS_C_QOP_DEFAULT,
290 &unwrapped, &conf_state,
291 &wrapped);
292 status = ADS_ERROR_GSS(gss_rc, minor_status);
293 if (!ADS_ERR_OK(status)) return status;
295 if (conf_req_flag && conf_state == 0) {
296 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
299 if ((ads->ldap.out.size - 4) < wrapped.length) {
300 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
303 /* copy the wrapped blob to the right location */
304 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
306 /* set how many bytes must be written to the underlying socket */
307 ads->ldap.out.left = 4 + wrapped.length;
309 gss_release_buffer(&minor_status, &wrapped);
311 return ADS_SUCCESS;
314 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
316 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
317 ADS_STATUS status;
318 int gss_rc;
319 uint32 minor_status;
320 gss_buffer_desc unwrapped, wrapped;
321 int conf_state;
323 wrapped.value = ads->ldap.in.buf + 4;
324 wrapped.length = ads->ldap.in.ofs - 4;
326 gss_rc = gss_unwrap(&minor_status, context_handle,
327 &wrapped, &unwrapped,
328 &conf_state, GSS_C_QOP_DEFAULT);
329 status = ADS_ERROR_GSS(gss_rc, minor_status);
330 if (!ADS_ERR_OK(status)) return status;
332 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
333 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
336 if (wrapped.length < unwrapped.length) {
337 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
340 /* copy the wrapped blob to the right location */
341 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
343 /* set how many bytes must be written to the underlying socket */
344 ads->ldap.in.left = unwrapped.length;
345 ads->ldap.in.ofs = 4;
347 gss_release_buffer(&minor_status, &unwrapped);
349 return ADS_SUCCESS;
352 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
354 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
355 uint32 minor_status;
357 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
359 ads->ldap.wrap_ops = NULL;
360 ads->ldap.wrap_private_data = NULL;
363 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
364 .name = "gssapi",
365 .wrap = ads_sasl_gssapi_wrap,
366 .unwrap = ads_sasl_gssapi_unwrap,
367 .disconnect = ads_sasl_gssapi_disconnect
371 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
373 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
375 ADS_STATUS status;
376 bool ok;
377 uint32 minor_status;
378 int gss_rc, rc;
379 gss_OID_desc krb5_mech_type =
380 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
381 gss_OID mech_type = &krb5_mech_type;
382 gss_OID actual_mech_type = GSS_C_NULL_OID;
383 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
384 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
385 gss_buffer_desc input_token, output_token;
386 uint32 req_flags, ret_flags;
387 uint32 req_tmp, ret_tmp;
388 DATA_BLOB unwrapped;
389 DATA_BLOB wrapped;
390 struct berval cred, *scred = NULL;
392 input_token.value = NULL;
393 input_token.length = 0;
395 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
396 switch (ads->ldap.wrap_type) {
397 case ADS_SASLWRAP_TYPE_SEAL:
398 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
399 break;
400 case ADS_SASLWRAP_TYPE_SIGN:
401 req_flags |= GSS_C_INTEG_FLAG;
402 break;
403 case ADS_SASLWRAP_TYPE_PLAIN:
404 break;
407 /* Note: here we explicit ask for the krb5 mech_type */
408 gss_rc = gss_init_sec_context(&minor_status,
409 GSS_C_NO_CREDENTIAL,
410 &context_handle,
411 serv_name,
412 mech_type,
413 req_flags,
415 NULL,
416 &input_token,
417 &actual_mech_type,
418 &output_token,
419 &ret_flags,
420 NULL);
421 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
422 status = ADS_ERROR_GSS(gss_rc, minor_status);
423 goto failed;
427 * As some gssapi krb5 mech implementations
428 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
429 * to req_flags internaly, it's not possible to
430 * use plain or signing only connection via
431 * the gssapi interface.
433 * Because of this we need to check it the ret_flags
434 * has more flags as req_flags and correct the value
435 * of ads->ldap.wrap_type.
437 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
438 * we need to give an error.
440 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
441 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
443 if (req_tmp == ret_tmp) {
444 /* everythings fine... */
446 } else if (req_flags & GSS_C_CONF_FLAG) {
448 * here we wanted sealing but didn't got it
449 * from the gssapi library
451 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
452 goto failed;
454 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
455 !(ret_flags & GSS_C_INTEG_FLAG)) {
457 * here we wanted siging but didn't got it
458 * from the gssapi library
460 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
461 goto failed;
463 } else if (ret_flags & GSS_C_CONF_FLAG) {
465 * here we didn't want sealing
466 * but the gssapi library forces it
467 * so correct the needed wrap_type if
468 * the caller didn't forced siging only
470 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
471 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
472 goto failed;
475 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
476 req_flags = ret_flags;
478 } else if (ret_flags & GSS_C_INTEG_FLAG) {
480 * here we didn't want signing
481 * but the gssapi library forces it
482 * so correct the needed wrap_type if
483 * the caller didn't forced plain
485 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
486 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
487 goto failed;
490 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
491 req_flags = ret_flags;
492 } else {
494 * This could (should?) not happen
496 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
497 goto failed;
501 /* and wrap that in a shiny SPNEGO wrapper */
502 unwrapped = data_blob_const(output_token.value, output_token.length);
503 wrapped = spnego_gen_negTokenInit(talloc_tos(),
504 spnego_mechs, &unwrapped, NULL);
505 gss_release_buffer(&minor_status, &output_token);
506 if (unwrapped.length > wrapped.length) {
507 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
508 goto failed;
511 cred.bv_val = (char *)wrapped.data;
512 cred.bv_len = wrapped.length;
514 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
515 &scred);
516 data_blob_free(&wrapped);
517 if (rc != LDAP_SUCCESS) {
518 status = ADS_ERROR(rc);
519 goto failed;
522 if (scred) {
523 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
524 } else {
525 wrapped = data_blob_null;
528 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
529 OID_KERBEROS5_OLD,
530 &unwrapped);
531 if (scred) ber_bvfree(scred);
532 if (!ok) {
533 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
534 goto failed;
537 input_token.value = unwrapped.data;
538 input_token.length = unwrapped.length;
541 * As we asked for mutal authentication
542 * we need to pass the servers response
543 * to gssapi
545 gss_rc = gss_init_sec_context(&minor_status,
546 GSS_C_NO_CREDENTIAL,
547 &context_handle,
548 serv_name,
549 mech_type,
550 req_flags,
552 NULL,
553 &input_token,
554 &actual_mech_type,
555 &output_token,
556 &ret_flags,
557 NULL);
558 data_blob_free(&unwrapped);
559 if (gss_rc) {
560 status = ADS_ERROR_GSS(gss_rc, minor_status);
561 goto failed;
564 gss_release_buffer(&minor_status, &output_token);
567 * If we the sign and seal options
568 * doesn't match after getting the response
569 * from the server, we don't want to use the connection
571 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
572 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
574 if (req_tmp != ret_tmp) {
575 /* everythings fine... */
576 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
577 goto failed;
580 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
581 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
583 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
584 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
585 GSS_C_QOP_DEFAULT,
586 max_msg_size, &ads->ldap.out.max_unwrapped);
587 if (gss_rc) {
588 status = ADS_ERROR_GSS(gss_rc, minor_status);
589 goto failed;
592 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
593 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
594 ads->ldap.in.max_wrapped = max_msg_size;
595 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
596 if (!ADS_ERR_OK(status)) {
597 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
598 ads_errstr(status)));
599 goto failed;
601 /* make sure we don't free context_handle */
602 context_handle = GSS_C_NO_CONTEXT;
605 status = ADS_SUCCESS;
607 failed:
608 if (context_handle != GSS_C_NO_CONTEXT)
609 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
610 return status;
613 #endif /* HAVE_KRB5 */
615 #ifdef HAVE_KRB5
616 struct ads_service_principal {
617 char *string;
618 #ifdef HAVE_KRB5
619 gss_name_t name;
620 #endif
623 static void ads_free_service_principal(struct ads_service_principal *p)
625 SAFE_FREE(p->string);
627 #ifdef HAVE_KRB5
628 if (p->name) {
629 uint32 minor_status;
630 gss_release_name(&minor_status, &p->name);
632 #endif
633 ZERO_STRUCTP(p);
637 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
638 char **returned_principal)
640 char *princ = NULL;
642 if (ads->server.realm && ads->server.ldap_server) {
643 char *server, *server_realm;
645 server = SMB_STRDUP(ads->server.ldap_server);
646 server_realm = SMB_STRDUP(ads->server.realm);
648 if (!server || !server_realm) {
649 SAFE_FREE(server);
650 SAFE_FREE(server_realm);
651 return ADS_ERROR(LDAP_NO_MEMORY);
654 strlower_m(server);
655 strupper_m(server_realm);
656 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
657 SAFE_FREE(server);
658 SAFE_FREE(server_realm);
659 return ADS_ERROR(LDAP_NO_MEMORY);
662 SAFE_FREE(server);
663 SAFE_FREE(server_realm);
665 if (!princ) {
666 return ADS_ERROR(LDAP_NO_MEMORY);
668 } else if (ads->config.realm && ads->config.ldap_server_name) {
669 char *server, *server_realm;
671 server = SMB_STRDUP(ads->config.ldap_server_name);
672 server_realm = SMB_STRDUP(ads->config.realm);
674 if (!server || !server_realm) {
675 SAFE_FREE(server);
676 SAFE_FREE(server_realm);
677 return ADS_ERROR(LDAP_NO_MEMORY);
680 strlower_m(server);
681 strupper_m(server_realm);
682 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
683 SAFE_FREE(server);
684 SAFE_FREE(server_realm);
685 return ADS_ERROR(LDAP_NO_MEMORY);
688 SAFE_FREE(server);
689 SAFE_FREE(server_realm);
691 if (!princ) {
692 return ADS_ERROR(LDAP_NO_MEMORY);
696 if (!princ) {
697 return ADS_ERROR(LDAP_PARAM_ERROR);
700 *returned_principal = princ;
702 return ADS_SUCCESS;
705 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
706 const char *given_principal,
707 struct ads_service_principal *p)
709 ADS_STATUS status;
710 #ifdef HAVE_KRB5
711 gss_buffer_desc input_name;
712 /* GSS_KRB5_NT_PRINCIPAL_NAME */
713 gss_OID_desc nt_principal =
714 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
715 uint32 minor_status;
716 int gss_rc;
717 #endif
719 ZERO_STRUCTP(p);
721 /* I've seen a child Windows 2000 domain not send
722 the principal name back in the first round of
723 the SASL bind reply. So we guess based on server
724 name and realm. --jerry */
725 /* Also try best guess when we get the w2k8 ignore principal
726 back, or when we are configured to ignore it - gd,
727 abartlet */
729 if (!lp_client_use_spnego_principal() ||
730 !given_principal ||
731 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
733 status = ads_guess_service_principal(ads, &p->string);
734 if (!ADS_ERR_OK(status)) {
735 return status;
737 } else {
738 p->string = SMB_STRDUP(given_principal);
739 if (!p->string) {
740 return ADS_ERROR(LDAP_NO_MEMORY);
744 #ifdef HAVE_KRB5
745 input_name.value = p->string;
746 input_name.length = strlen(p->string);
748 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
749 if (gss_rc) {
750 ads_free_service_principal(p);
751 return ADS_ERROR_GSS(gss_rc, minor_status);
753 #endif
755 return ADS_SUCCESS;
759 perform a LDAP/SASL/SPNEGO/KRB5 bind
761 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
763 DATA_BLOB blob = data_blob_null;
764 struct berval cred, *scred = NULL;
765 DATA_BLOB session_key = data_blob_null;
766 int rc;
768 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
769 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
772 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
773 ads->auth.time_offset, &blob, &session_key, 0,
774 &ads->auth.tgs_expire);
776 if (rc) {
777 return ADS_ERROR_KRB5(rc);
780 /* now send the auth packet and we should be done */
781 cred.bv_val = (char *)blob.data;
782 cred.bv_len = blob.length;
784 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
786 data_blob_free(&blob);
787 data_blob_free(&session_key);
788 if(scred)
789 ber_bvfree(scred);
791 return ADS_ERROR(rc);
794 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
795 struct ads_service_principal *p)
797 #ifdef HAVE_KRB5
799 * we only use the gsskrb5 based implementation
800 * when sasl sign or seal is requested.
802 * This has the following reasons:
803 * - it's likely that the gssapi krb5 mech implementation
804 * doesn't support to negotiate plain connections
805 * - the ads_sasl_spnego_rawkrb5_bind is more robust
806 * against clock skew errors
808 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
809 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
811 #endif
812 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
814 #endif /* HAVE_KRB5 */
817 this performs a SASL/SPNEGO bind
819 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
821 struct berval *scred=NULL;
822 int rc, i;
823 ADS_STATUS status;
824 DATA_BLOB blob;
825 char *given_principal = NULL;
826 char *OIDs[ASN1_MAX_OIDS];
827 #ifdef HAVE_KRB5
828 bool got_kerberos_mechanism = False;
829 #endif
831 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
833 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
834 status = ADS_ERROR(rc);
835 goto failed;
838 blob = data_blob(scred->bv_val, scred->bv_len);
840 ber_bvfree(scred);
842 #if 0
843 file_save("sasl_spnego.dat", blob.data, blob.length);
844 #endif
846 /* the server sent us the first part of the SPNEGO exchange in the negprot
847 reply */
848 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
849 OIDs[0] == NULL) {
850 data_blob_free(&blob);
851 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
852 goto failed;
854 data_blob_free(&blob);
856 /* make sure the server understands kerberos */
857 for (i=0;OIDs[i];i++) {
858 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
859 #ifdef HAVE_KRB5
860 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
861 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
862 got_kerberos_mechanism = True;
864 #endif
865 talloc_free(OIDs[i]);
867 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
869 #ifdef HAVE_KRB5
870 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
871 got_kerberos_mechanism)
873 struct ads_service_principal p;
875 status = ads_generate_service_principal(ads, given_principal, &p);
876 TALLOC_FREE(given_principal);
877 if (!ADS_ERR_OK(status)) {
878 return status;
881 status = ads_sasl_spnego_krb5_bind(ads, &p);
882 if (ADS_ERR_OK(status)) {
883 ads_free_service_principal(&p);
884 return status;
887 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
888 "calling kinit\n", ads_errstr(status)));
890 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
892 if (ADS_ERR_OK(status)) {
893 status = ads_sasl_spnego_krb5_bind(ads, &p);
894 if (!ADS_ERR_OK(status)) {
895 DEBUG(0,("kinit succeeded but "
896 "ads_sasl_spnego_krb5_bind failed: %s\n",
897 ads_errstr(status)));
901 ads_free_service_principal(&p);
903 /* only fallback to NTLMSSP if allowed */
904 if (ADS_ERR_OK(status) ||
905 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
906 return status;
908 } else
909 #endif
911 TALLOC_FREE(given_principal);
914 /* lets do NTLMSSP ... this has the big advantage that we don't need
915 to sync clocks, and we don't rely on special versions of the krb5
916 library for HMAC_MD4 encryption */
917 return ads_sasl_spnego_ntlmssp_bind(ads);
919 failed:
920 return status;
923 #ifdef HAVE_KRB5
924 #define MAX_GSS_PASSES 3
926 /* this performs a SASL/gssapi bind
927 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
928 is very dependent on correctly configured DNS whereas
929 this routine is much less fragile
930 see RFC2078 and RFC2222 for details
932 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
934 uint32 minor_status;
935 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
936 gss_OID mech_type = GSS_C_NULL_OID;
937 gss_buffer_desc output_token, input_token;
938 uint32 req_flags, ret_flags;
939 int conf_state;
940 struct berval cred;
941 struct berval *scred = NULL;
942 int i=0;
943 int gss_rc, rc;
944 uint8 *p;
945 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
946 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
947 ADS_STATUS status;
949 input_token.value = NULL;
950 input_token.length = 0;
953 * Note: here we always ask the gssapi for sign and seal
954 * as this is negotiated later after the mutal
955 * authentication
957 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
959 for (i=0; i < MAX_GSS_PASSES; i++) {
960 gss_rc = gss_init_sec_context(&minor_status,
961 GSS_C_NO_CREDENTIAL,
962 &context_handle,
963 serv_name,
964 mech_type,
965 req_flags,
967 NULL,
968 &input_token,
969 NULL,
970 &output_token,
971 &ret_flags,
972 NULL);
973 if (scred) {
974 ber_bvfree(scred);
975 scred = NULL;
977 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
978 status = ADS_ERROR_GSS(gss_rc, minor_status);
979 goto failed;
982 cred.bv_val = (char *)output_token.value;
983 cred.bv_len = output_token.length;
985 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
986 &scred);
987 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
988 status = ADS_ERROR(rc);
989 goto failed;
992 if (output_token.value) {
993 gss_release_buffer(&minor_status, &output_token);
996 if (scred) {
997 input_token.value = scred->bv_val;
998 input_token.length = scred->bv_len;
999 } else {
1000 input_token.value = NULL;
1001 input_token.length = 0;
1004 if (gss_rc == 0) break;
1007 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1008 &conf_state,NULL);
1009 if (scred) {
1010 ber_bvfree(scred);
1011 scred = NULL;
1013 if (gss_rc) {
1014 status = ADS_ERROR_GSS(gss_rc, minor_status);
1015 goto failed;
1018 p = (uint8 *)output_token.value;
1020 #if 0
1021 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1022 #endif
1024 if (p) {
1025 wrap_type = CVAL(p,0);
1026 SCVAL(p,0,0);
1027 max_msg_size = RIVAL(p,0);
1030 gss_release_buffer(&minor_status, &output_token);
1032 if (!(wrap_type & ads->ldap.wrap_type)) {
1034 * the server doesn't supports the wrap
1035 * type we want :-(
1037 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1038 ads->ldap.wrap_type, wrap_type));
1039 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1040 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1041 goto failed;
1044 /* 0x58 is the minimum windows accepts */
1045 if (max_msg_size < 0x58) {
1046 max_msg_size = 0x58;
1049 output_token.length = 4;
1050 output_token.value = SMB_MALLOC(output_token.length);
1051 if (!output_token.value) {
1052 output_token.length = 0;
1053 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1054 goto failed;
1056 p = (uint8 *)output_token.value;
1058 RSIVAL(p,0,max_msg_size);
1059 SCVAL(p,0,ads->ldap.wrap_type);
1062 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1063 * but using ads->config.bind_path is the wrong! It should be
1064 * the DN of the user object!
1066 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1067 * is ok and matches the information flow used in GSS-SPNEGO.
1070 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1071 &output_token, /* used as *input* here. */
1072 &conf_state,
1073 &input_token); /* Used as *output* here. */
1074 if (gss_rc) {
1075 status = ADS_ERROR_GSS(gss_rc, minor_status);
1076 output_token.length = 0;
1077 SAFE_FREE(output_token.value);
1078 goto failed;
1081 /* We've finished with output_token. */
1082 SAFE_FREE(output_token.value);
1083 output_token.length = 0;
1085 cred.bv_val = (char *)input_token.value;
1086 cred.bv_len = input_token.length;
1088 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1089 &scred);
1090 gss_release_buffer(&minor_status, &input_token);
1091 status = ADS_ERROR(rc);
1092 if (!ADS_ERR_OK(status)) {
1093 goto failed;
1096 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1097 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1098 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1099 GSS_C_QOP_DEFAULT,
1100 max_msg_size, &ads->ldap.out.max_unwrapped);
1101 if (gss_rc) {
1102 status = ADS_ERROR_GSS(gss_rc, minor_status);
1103 goto failed;
1106 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1107 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1108 ads->ldap.in.max_wrapped = max_msg_size;
1109 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1110 if (!ADS_ERR_OK(status)) {
1111 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1112 ads_errstr(status)));
1113 goto failed;
1115 /* make sure we don't free context_handle */
1116 context_handle = GSS_C_NO_CONTEXT;
1119 failed:
1121 if (context_handle != GSS_C_NO_CONTEXT)
1122 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1124 if(scred)
1125 ber_bvfree(scred);
1126 return status;
1129 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1131 ADS_STATUS status;
1132 struct ads_service_principal p;
1134 status = ads_generate_service_principal(ads, NULL, &p);
1135 if (!ADS_ERR_OK(status)) {
1136 return status;
1139 status = ads_sasl_gssapi_do_bind(ads, p.name);
1140 if (ADS_ERR_OK(status)) {
1141 ads_free_service_principal(&p);
1142 return status;
1145 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1146 "calling kinit\n", ads_errstr(status)));
1148 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1150 if (ADS_ERR_OK(status)) {
1151 status = ads_sasl_gssapi_do_bind(ads, p.name);
1154 ads_free_service_principal(&p);
1156 return status;
1159 #endif /* HAVE_KRB5 */
1161 /* mapping between SASL mechanisms and functions */
1162 static struct {
1163 const char *name;
1164 ADS_STATUS (*fn)(ADS_STRUCT *);
1165 } sasl_mechanisms[] = {
1166 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1167 #ifdef HAVE_KRB5
1168 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1169 #endif
1170 {NULL, NULL}
1173 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1175 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1176 char **values;
1177 ADS_STATUS status;
1178 int i, j;
1179 LDAPMessage *res;
1181 /* get a list of supported SASL mechanisms */
1182 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1183 if (!ADS_ERR_OK(status)) return status;
1185 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1187 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1188 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1189 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1190 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1191 } else {
1192 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1195 /* try our supported mechanisms in order */
1196 for (i=0;sasl_mechanisms[i].name;i++) {
1197 /* see if the server supports it */
1198 for (j=0;values && values[j];j++) {
1199 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1200 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1201 retry:
1202 status = sasl_mechanisms[i].fn(ads);
1203 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1204 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1205 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1207 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1208 "retrying with signing enabled\n"));
1209 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1210 goto retry;
1212 ldap_value_free(values);
1213 ldap_msgfree(res);
1214 return status;
1219 ldap_value_free(values);
1220 ldap_msgfree(res);
1221 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1224 #endif /* HAVE_LDAP */