s3: Attempt to fix the build without kerberos
[Samba/gebeck_regimport.git] / source3 / libads / sasl.c
blob02fd7545e5ee08be8291d8a0d0c1ee0004fc4aa9
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"
27 #ifdef HAVE_LDAP
29 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
31 struct gensec_security *gensec_security =
32 talloc_get_type_abort(ads->ldap.wrap_private_data,
33 struct gensec_security);
34 NTSTATUS nt_status;
35 DATA_BLOB unwrapped, wrapped;
36 TALLOC_CTX *frame = talloc_stackframe();
38 unwrapped = data_blob_const(buf, len);
40 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
41 if (!NT_STATUS_IS_OK(nt_status)) {
42 TALLOC_FREE(frame);
43 return ADS_ERROR_NT(nt_status);
46 if ((ads->ldap.out.size - 4) < wrapped.length) {
47 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
50 /* copy the wrapped blob to the right location */
51 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
53 /* set how many bytes must be written to the underlying socket */
54 ads->ldap.out.left = 4 + wrapped.length;
56 TALLOC_FREE(frame);
58 return ADS_SUCCESS;
61 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
63 struct gensec_security *gensec_security =
64 talloc_get_type_abort(ads->ldap.wrap_private_data,
65 struct gensec_security);
66 NTSTATUS nt_status;
67 DATA_BLOB unwrapped, wrapped;
68 TALLOC_CTX *frame = talloc_stackframe();
70 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
72 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
73 if (!NT_STATUS_IS_OK(nt_status)) {
74 TALLOC_FREE(frame);
75 return ADS_ERROR_NT(nt_status);
78 if (wrapped.length < unwrapped.length) {
79 TALLOC_FREE(frame);
80 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
83 /* copy the wrapped blob to the right location */
84 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
86 /* set how many bytes must be written to the underlying socket */
87 ads->ldap.in.left = unwrapped.length;
88 ads->ldap.in.ofs = 4;
90 TALLOC_FREE(frame);
92 return ADS_SUCCESS;
95 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
97 struct gensec_security *gensec_security =
98 talloc_get_type_abort(ads->ldap.wrap_private_data,
99 struct gensec_security);
101 TALLOC_FREE(gensec_security);
103 ads->ldap.wrap_ops = NULL;
104 ads->ldap.wrap_private_data = NULL;
107 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
108 .name = "ntlmssp",
109 .wrap = ads_sasl_ntlmssp_wrap,
110 .unwrap = ads_sasl_ntlmssp_unwrap,
111 .disconnect = ads_sasl_ntlmssp_disconnect
115 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
116 we fit on one socket??)
118 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
120 DATA_BLOB msg1 = data_blob_null;
121 DATA_BLOB blob = data_blob_null;
122 DATA_BLOB blob_in = data_blob_null;
123 DATA_BLOB blob_out = data_blob_null;
124 struct berval cred, *scred = NULL;
125 int rc;
126 NTSTATUS nt_status;
127 ADS_STATUS status;
128 int turn = 1;
130 struct auth_generic_state *auth_generic_state;
132 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
133 if (!NT_STATUS_IS_OK(nt_status)) {
134 return ADS_ERROR_NT(nt_status);
137 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
138 return ADS_ERROR_NT(nt_status);
140 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
141 return ADS_ERROR_NT(nt_status);
143 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
144 return ADS_ERROR_NT(nt_status);
147 switch (ads->ldap.wrap_type) {
148 case ADS_SASLWRAP_TYPE_SEAL:
149 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
150 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
151 break;
152 case ADS_SASLWRAP_TYPE_SIGN:
153 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
154 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
155 } else {
157 * windows servers are broken with sign only,
158 * so we need to use seal here too
160 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
161 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
162 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
164 break;
165 case ADS_SASLWRAP_TYPE_PLAIN:
166 break;
169 nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
170 if (!NT_STATUS_IS_OK(nt_status)) {
171 return ADS_ERROR_NT(nt_status);
174 blob_in = data_blob_null;
176 do {
177 nt_status = gensec_update(auth_generic_state->gensec_security,
178 talloc_tos(), NULL, blob_in, &blob_out);
179 data_blob_free(&blob_in);
180 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
181 || NT_STATUS_IS_OK(nt_status))
182 && blob_out.length) {
183 if (turn == 1) {
184 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
185 /* and wrap it in a SPNEGO wrapper */
186 msg1 = spnego_gen_negTokenInit(talloc_tos(),
187 OIDs_ntlm, &blob_out, NULL);
188 } else {
189 /* wrap it in SPNEGO */
190 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
193 data_blob_free(&blob_out);
195 cred.bv_val = (char *)msg1.data;
196 cred.bv_len = msg1.length;
197 scred = NULL;
198 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
199 data_blob_free(&msg1);
200 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
201 if (scred) {
202 ber_bvfree(scred);
205 TALLOC_FREE(auth_generic_state);
206 return ADS_ERROR(rc);
208 if (scred) {
209 blob = data_blob(scred->bv_val, scred->bv_len);
210 ber_bvfree(scred);
211 } else {
212 blob = data_blob_null;
215 } else {
217 TALLOC_FREE(auth_generic_state);
218 data_blob_free(&blob_out);
219 return ADS_ERROR_NT(nt_status);
222 if ((turn == 1) &&
223 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
224 DATA_BLOB tmp_blob = data_blob_null;
225 /* the server might give us back two challenges */
226 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
227 &tmp_blob)) {
229 TALLOC_FREE(auth_generic_state);
230 data_blob_free(&blob);
231 DEBUG(3,("Failed to parse challenges\n"));
232 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
234 data_blob_free(&tmp_blob);
235 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
236 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
237 &blob_in)) {
239 TALLOC_FREE(auth_generic_state);
240 data_blob_free(&blob);
241 DEBUG(3,("Failed to parse auth response\n"));
242 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
245 data_blob_free(&blob);
246 data_blob_free(&blob_out);
247 turn++;
248 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
250 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
251 uint32_t sig_size = gensec_sig_size(auth_generic_state->gensec_security, 0);
252 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - sig_size;
253 ads->ldap.out.sig_size = sig_size;
254 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
255 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
256 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
257 if (!ADS_ERR_OK(status)) {
258 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
259 ads_errstr(status)));
260 TALLOC_FREE(auth_generic_state);
261 return status;
263 /* Only keep the gensec_security element around long-term */
264 talloc_steal(NULL, auth_generic_state->gensec_security);
266 TALLOC_FREE(auth_generic_state);
268 return ADS_ERROR(rc);
271 #ifdef HAVE_KRB5
272 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
274 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
275 ADS_STATUS status;
276 int gss_rc;
277 uint32 minor_status;
278 gss_buffer_desc unwrapped, wrapped;
279 int conf_req_flag, conf_state;
281 unwrapped.value = buf;
282 unwrapped.length = len;
284 /* for now request sign and seal */
285 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
287 gss_rc = gss_wrap(&minor_status, context_handle,
288 conf_req_flag, GSS_C_QOP_DEFAULT,
289 &unwrapped, &conf_state,
290 &wrapped);
291 status = ADS_ERROR_GSS(gss_rc, minor_status);
292 if (!ADS_ERR_OK(status)) return status;
294 if (conf_req_flag && conf_state == 0) {
295 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
298 if ((ads->ldap.out.size - 4) < wrapped.length) {
299 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
302 /* copy the wrapped blob to the right location */
303 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
305 /* set how many bytes must be written to the underlying socket */
306 ads->ldap.out.left = 4 + wrapped.length;
308 gss_release_buffer(&minor_status, &wrapped);
310 return ADS_SUCCESS;
313 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
315 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
316 ADS_STATUS status;
317 int gss_rc;
318 uint32 minor_status;
319 gss_buffer_desc unwrapped, wrapped;
320 int conf_state;
322 wrapped.value = ads->ldap.in.buf + 4;
323 wrapped.length = ads->ldap.in.ofs - 4;
325 gss_rc = gss_unwrap(&minor_status, context_handle,
326 &wrapped, &unwrapped,
327 &conf_state, GSS_C_QOP_DEFAULT);
328 status = ADS_ERROR_GSS(gss_rc, minor_status);
329 if (!ADS_ERR_OK(status)) return status;
331 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
332 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
335 if (wrapped.length < unwrapped.length) {
336 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
339 /* copy the wrapped blob to the right location */
340 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
342 /* set how many bytes must be written to the underlying socket */
343 ads->ldap.in.left = unwrapped.length;
344 ads->ldap.in.ofs = 4;
346 gss_release_buffer(&minor_status, &unwrapped);
348 return ADS_SUCCESS;
351 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
353 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
354 uint32 minor_status;
356 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
358 ads->ldap.wrap_ops = NULL;
359 ads->ldap.wrap_private_data = NULL;
362 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
363 .name = "gssapi",
364 .wrap = ads_sasl_gssapi_wrap,
365 .unwrap = ads_sasl_gssapi_unwrap,
366 .disconnect = ads_sasl_gssapi_disconnect
370 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
372 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
374 ADS_STATUS status;
375 bool ok;
376 uint32 minor_status;
377 int gss_rc, rc;
378 gss_OID_desc krb5_mech_type =
379 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
380 gss_OID mech_type = &krb5_mech_type;
381 gss_OID actual_mech_type = GSS_C_NULL_OID;
382 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
383 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
384 gss_buffer_desc input_token, output_token;
385 uint32 req_flags, ret_flags;
386 uint32 req_tmp, ret_tmp;
387 DATA_BLOB unwrapped;
388 DATA_BLOB wrapped;
389 struct berval cred, *scred = NULL;
391 input_token.value = NULL;
392 input_token.length = 0;
394 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
395 switch (ads->ldap.wrap_type) {
396 case ADS_SASLWRAP_TYPE_SEAL:
397 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
398 break;
399 case ADS_SASLWRAP_TYPE_SIGN:
400 req_flags |= GSS_C_INTEG_FLAG;
401 break;
402 case ADS_SASLWRAP_TYPE_PLAIN:
403 break;
406 /* Note: here we explicit ask for the krb5 mech_type */
407 gss_rc = gss_init_sec_context(&minor_status,
408 GSS_C_NO_CREDENTIAL,
409 &context_handle,
410 serv_name,
411 mech_type,
412 req_flags,
414 NULL,
415 &input_token,
416 &actual_mech_type,
417 &output_token,
418 &ret_flags,
419 NULL);
420 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
421 status = ADS_ERROR_GSS(gss_rc, minor_status);
422 goto failed;
426 * As some gssapi krb5 mech implementations
427 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
428 * to req_flags internaly, it's not possible to
429 * use plain or signing only connection via
430 * the gssapi interface.
432 * Because of this we need to check it the ret_flags
433 * has more flags as req_flags and correct the value
434 * of ads->ldap.wrap_type.
436 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
437 * we need to give an error.
439 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
440 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
442 if (req_tmp == ret_tmp) {
443 /* everythings fine... */
445 } else if (req_flags & GSS_C_CONF_FLAG) {
447 * here we wanted sealing but didn't got it
448 * from the gssapi library
450 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
451 goto failed;
453 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
454 !(ret_flags & GSS_C_INTEG_FLAG)) {
456 * here we wanted siging but didn't got it
457 * from the gssapi library
459 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
460 goto failed;
462 } else if (ret_flags & GSS_C_CONF_FLAG) {
464 * here we didn't want sealing
465 * but the gssapi library forces it
466 * so correct the needed wrap_type if
467 * the caller didn't forced siging only
469 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
470 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
471 goto failed;
474 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
475 req_flags = ret_flags;
477 } else if (ret_flags & GSS_C_INTEG_FLAG) {
479 * here we didn't want signing
480 * but the gssapi library forces it
481 * so correct the needed wrap_type if
482 * the caller didn't forced plain
484 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
485 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
486 goto failed;
489 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
490 req_flags = ret_flags;
491 } else {
493 * This could (should?) not happen
495 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
496 goto failed;
500 /* and wrap that in a shiny SPNEGO wrapper */
501 unwrapped = data_blob_const(output_token.value, output_token.length);
502 wrapped = spnego_gen_negTokenInit(talloc_tos(),
503 spnego_mechs, &unwrapped, NULL);
504 gss_release_buffer(&minor_status, &output_token);
505 if (unwrapped.length > wrapped.length) {
506 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
507 goto failed;
510 cred.bv_val = (char *)wrapped.data;
511 cred.bv_len = wrapped.length;
513 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
514 &scred);
515 data_blob_free(&wrapped);
516 if (rc != LDAP_SUCCESS) {
517 status = ADS_ERROR(rc);
518 goto failed;
521 if (scred) {
522 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
523 } else {
524 wrapped = data_blob_null;
527 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
528 OID_KERBEROS5_OLD,
529 &unwrapped);
530 if (scred) ber_bvfree(scred);
531 if (!ok) {
532 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
533 goto failed;
536 input_token.value = unwrapped.data;
537 input_token.length = unwrapped.length;
540 * As we asked for mutal authentication
541 * we need to pass the servers response
542 * to gssapi
544 gss_rc = gss_init_sec_context(&minor_status,
545 GSS_C_NO_CREDENTIAL,
546 &context_handle,
547 serv_name,
548 mech_type,
549 req_flags,
551 NULL,
552 &input_token,
553 &actual_mech_type,
554 &output_token,
555 &ret_flags,
556 NULL);
557 data_blob_free(&unwrapped);
558 if (gss_rc) {
559 status = ADS_ERROR_GSS(gss_rc, minor_status);
560 goto failed;
563 gss_release_buffer(&minor_status, &output_token);
566 * If we the sign and seal options
567 * doesn't match after getting the response
568 * from the server, we don't want to use the connection
570 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
571 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
573 if (req_tmp != ret_tmp) {
574 /* everythings fine... */
575 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
576 goto failed;
579 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
580 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
582 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
583 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
584 GSS_C_QOP_DEFAULT,
585 max_msg_size, &ads->ldap.out.max_unwrapped);
586 if (gss_rc) {
587 status = ADS_ERROR_GSS(gss_rc, minor_status);
588 goto failed;
591 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
592 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
593 ads->ldap.in.max_wrapped = max_msg_size;
594 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
595 if (!ADS_ERR_OK(status)) {
596 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
597 ads_errstr(status)));
598 goto failed;
600 /* make sure we don't free context_handle */
601 context_handle = GSS_C_NO_CONTEXT;
604 status = ADS_SUCCESS;
606 failed:
607 if (context_handle != GSS_C_NO_CONTEXT)
608 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
609 return status;
612 #endif /* HAVE_KRB5 */
614 #ifdef HAVE_KRB5
615 struct ads_service_principal {
616 char *string;
617 #ifdef HAVE_KRB5
618 gss_name_t name;
619 #endif
622 static void ads_free_service_principal(struct ads_service_principal *p)
624 SAFE_FREE(p->string);
626 #ifdef HAVE_KRB5
627 if (p->name) {
628 uint32 minor_status;
629 gss_release_name(&minor_status, &p->name);
631 #endif
632 ZERO_STRUCTP(p);
636 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
637 char **returned_principal)
639 char *princ = NULL;
641 if (ads->server.realm && ads->server.ldap_server) {
642 char *server, *server_realm;
644 server = SMB_STRDUP(ads->server.ldap_server);
645 server_realm = SMB_STRDUP(ads->server.realm);
647 if (!server || !server_realm) {
648 SAFE_FREE(server);
649 SAFE_FREE(server_realm);
650 return ADS_ERROR(LDAP_NO_MEMORY);
653 strlower_m(server);
654 strupper_m(server_realm);
655 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
656 SAFE_FREE(server);
657 SAFE_FREE(server_realm);
658 return ADS_ERROR(LDAP_NO_MEMORY);
661 SAFE_FREE(server);
662 SAFE_FREE(server_realm);
664 if (!princ) {
665 return ADS_ERROR(LDAP_NO_MEMORY);
667 } else if (ads->config.realm && ads->config.ldap_server_name) {
668 char *server, *server_realm;
670 server = SMB_STRDUP(ads->config.ldap_server_name);
671 server_realm = SMB_STRDUP(ads->config.realm);
673 if (!server || !server_realm) {
674 SAFE_FREE(server);
675 SAFE_FREE(server_realm);
676 return ADS_ERROR(LDAP_NO_MEMORY);
679 strlower_m(server);
680 strupper_m(server_realm);
681 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
682 SAFE_FREE(server);
683 SAFE_FREE(server_realm);
684 return ADS_ERROR(LDAP_NO_MEMORY);
687 SAFE_FREE(server);
688 SAFE_FREE(server_realm);
690 if (!princ) {
691 return ADS_ERROR(LDAP_NO_MEMORY);
695 if (!princ) {
696 return ADS_ERROR(LDAP_PARAM_ERROR);
699 *returned_principal = princ;
701 return ADS_SUCCESS;
704 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
705 const char *given_principal,
706 struct ads_service_principal *p)
708 ADS_STATUS status;
709 #ifdef HAVE_KRB5
710 gss_buffer_desc input_name;
711 /* GSS_KRB5_NT_PRINCIPAL_NAME */
712 gss_OID_desc nt_principal =
713 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
714 uint32 minor_status;
715 int gss_rc;
716 #endif
718 ZERO_STRUCTP(p);
720 /* I've seen a child Windows 2000 domain not send
721 the principal name back in the first round of
722 the SASL bind reply. So we guess based on server
723 name and realm. --jerry */
724 /* Also try best guess when we get the w2k8 ignore principal
725 back, or when we are configured to ignore it - gd,
726 abartlet */
728 if (!lp_client_use_spnego_principal() ||
729 !given_principal ||
730 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
732 status = ads_guess_service_principal(ads, &p->string);
733 if (!ADS_ERR_OK(status)) {
734 return status;
736 } else {
737 p->string = SMB_STRDUP(given_principal);
738 if (!p->string) {
739 return ADS_ERROR(LDAP_NO_MEMORY);
743 #ifdef HAVE_KRB5
744 input_name.value = p->string;
745 input_name.length = strlen(p->string);
747 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
748 if (gss_rc) {
749 ads_free_service_principal(p);
750 return ADS_ERROR_GSS(gss_rc, minor_status);
752 #endif
754 return ADS_SUCCESS;
758 perform a LDAP/SASL/SPNEGO/KRB5 bind
760 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
762 DATA_BLOB blob = data_blob_null;
763 struct berval cred, *scred = NULL;
764 DATA_BLOB session_key = data_blob_null;
765 int rc;
767 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
768 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
771 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
772 ads->auth.time_offset, &blob, &session_key, 0,
773 &ads->auth.tgs_expire);
775 if (rc) {
776 return ADS_ERROR_KRB5(rc);
779 /* now send the auth packet and we should be done */
780 cred.bv_val = (char *)blob.data;
781 cred.bv_len = blob.length;
783 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
785 data_blob_free(&blob);
786 data_blob_free(&session_key);
787 if(scred)
788 ber_bvfree(scred);
790 return ADS_ERROR(rc);
793 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
794 struct ads_service_principal *p)
796 #ifdef HAVE_KRB5
798 * we only use the gsskrb5 based implementation
799 * when sasl sign or seal is requested.
801 * This has the following reasons:
802 * - it's likely that the gssapi krb5 mech implementation
803 * doesn't support to negotiate plain connections
804 * - the ads_sasl_spnego_rawkrb5_bind is more robust
805 * against clock skew errors
807 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
808 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
810 #endif
811 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
813 #endif /* HAVE_KRB5 */
816 this performs a SASL/SPNEGO bind
818 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
820 struct berval *scred=NULL;
821 int rc, i;
822 ADS_STATUS status;
823 DATA_BLOB blob;
824 char *given_principal = NULL;
825 char *OIDs[ASN1_MAX_OIDS];
826 #ifdef HAVE_KRB5
827 bool got_kerberos_mechanism = False;
828 #endif
830 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
832 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
833 status = ADS_ERROR(rc);
834 goto failed;
837 blob = data_blob(scred->bv_val, scred->bv_len);
839 ber_bvfree(scred);
841 #if 0
842 file_save("sasl_spnego.dat", blob.data, blob.length);
843 #endif
845 /* the server sent us the first part of the SPNEGO exchange in the negprot
846 reply */
847 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
848 OIDs[0] == NULL) {
849 data_blob_free(&blob);
850 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
851 goto failed;
853 data_blob_free(&blob);
855 /* make sure the server understands kerberos */
856 for (i=0;OIDs[i];i++) {
857 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
858 #ifdef HAVE_KRB5
859 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
860 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
861 got_kerberos_mechanism = True;
863 #endif
864 talloc_free(OIDs[i]);
866 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
868 #ifdef HAVE_KRB5
869 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
870 got_kerberos_mechanism)
872 struct ads_service_principal p;
874 status = ads_generate_service_principal(ads, given_principal, &p);
875 TALLOC_FREE(given_principal);
876 if (!ADS_ERR_OK(status)) {
877 return status;
880 status = ads_sasl_spnego_krb5_bind(ads, &p);
881 if (ADS_ERR_OK(status)) {
882 ads_free_service_principal(&p);
883 return status;
886 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
887 "calling kinit\n", ads_errstr(status)));
889 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
891 if (ADS_ERR_OK(status)) {
892 status = ads_sasl_spnego_krb5_bind(ads, &p);
893 if (!ADS_ERR_OK(status)) {
894 DEBUG(0,("kinit succeeded but "
895 "ads_sasl_spnego_krb5_bind failed: %s\n",
896 ads_errstr(status)));
900 ads_free_service_principal(&p);
902 /* only fallback to NTLMSSP if allowed */
903 if (ADS_ERR_OK(status) ||
904 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
905 return status;
907 } else
908 #endif
910 TALLOC_FREE(given_principal);
913 /* lets do NTLMSSP ... this has the big advantage that we don't need
914 to sync clocks, and we don't rely on special versions of the krb5
915 library for HMAC_MD4 encryption */
916 return ads_sasl_spnego_ntlmssp_bind(ads);
918 failed:
919 return status;
922 #ifdef HAVE_KRB5
923 #define MAX_GSS_PASSES 3
925 /* this performs a SASL/gssapi bind
926 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
927 is very dependent on correctly configured DNS whereas
928 this routine is much less fragile
929 see RFC2078 and RFC2222 for details
931 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
933 uint32 minor_status;
934 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
935 gss_OID mech_type = GSS_C_NULL_OID;
936 gss_buffer_desc output_token, input_token;
937 uint32 req_flags, ret_flags;
938 int conf_state;
939 struct berval cred;
940 struct berval *scred = NULL;
941 int i=0;
942 int gss_rc, rc;
943 uint8 *p;
944 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
945 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
946 ADS_STATUS status;
948 input_token.value = NULL;
949 input_token.length = 0;
952 * Note: here we always ask the gssapi for sign and seal
953 * as this is negotiated later after the mutal
954 * authentication
956 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
958 for (i=0; i < MAX_GSS_PASSES; i++) {
959 gss_rc = gss_init_sec_context(&minor_status,
960 GSS_C_NO_CREDENTIAL,
961 &context_handle,
962 serv_name,
963 mech_type,
964 req_flags,
966 NULL,
967 &input_token,
968 NULL,
969 &output_token,
970 &ret_flags,
971 NULL);
972 if (scred) {
973 ber_bvfree(scred);
974 scred = NULL;
976 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
977 status = ADS_ERROR_GSS(gss_rc, minor_status);
978 goto failed;
981 cred.bv_val = (char *)output_token.value;
982 cred.bv_len = output_token.length;
984 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
985 &scred);
986 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
987 status = ADS_ERROR(rc);
988 goto failed;
991 if (output_token.value) {
992 gss_release_buffer(&minor_status, &output_token);
995 if (scred) {
996 input_token.value = scred->bv_val;
997 input_token.length = scred->bv_len;
998 } else {
999 input_token.value = NULL;
1000 input_token.length = 0;
1003 if (gss_rc == 0) break;
1006 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1007 &conf_state,NULL);
1008 if (scred) {
1009 ber_bvfree(scred);
1010 scred = NULL;
1012 if (gss_rc) {
1013 status = ADS_ERROR_GSS(gss_rc, minor_status);
1014 goto failed;
1017 p = (uint8 *)output_token.value;
1019 #if 0
1020 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1021 #endif
1023 if (p) {
1024 wrap_type = CVAL(p,0);
1025 SCVAL(p,0,0);
1026 max_msg_size = RIVAL(p,0);
1029 gss_release_buffer(&minor_status, &output_token);
1031 if (!(wrap_type & ads->ldap.wrap_type)) {
1033 * the server doesn't supports the wrap
1034 * type we want :-(
1036 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1037 ads->ldap.wrap_type, wrap_type));
1038 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1039 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1040 goto failed;
1043 /* 0x58 is the minimum windows accepts */
1044 if (max_msg_size < 0x58) {
1045 max_msg_size = 0x58;
1048 output_token.length = 4;
1049 output_token.value = SMB_MALLOC(output_token.length);
1050 if (!output_token.value) {
1051 output_token.length = 0;
1052 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1053 goto failed;
1055 p = (uint8 *)output_token.value;
1057 RSIVAL(p,0,max_msg_size);
1058 SCVAL(p,0,ads->ldap.wrap_type);
1061 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1062 * but using ads->config.bind_path is the wrong! It should be
1063 * the DN of the user object!
1065 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1066 * is ok and matches the information flow used in GSS-SPNEGO.
1069 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1070 &output_token, /* used as *input* here. */
1071 &conf_state,
1072 &input_token); /* Used as *output* here. */
1073 if (gss_rc) {
1074 status = ADS_ERROR_GSS(gss_rc, minor_status);
1075 output_token.length = 0;
1076 SAFE_FREE(output_token.value);
1077 goto failed;
1080 /* We've finished with output_token. */
1081 SAFE_FREE(output_token.value);
1082 output_token.length = 0;
1084 cred.bv_val = (char *)input_token.value;
1085 cred.bv_len = input_token.length;
1087 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1088 &scred);
1089 gss_release_buffer(&minor_status, &input_token);
1090 status = ADS_ERROR(rc);
1091 if (!ADS_ERR_OK(status)) {
1092 goto failed;
1095 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1096 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1097 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1098 GSS_C_QOP_DEFAULT,
1099 max_msg_size, &ads->ldap.out.max_unwrapped);
1100 if (gss_rc) {
1101 status = ADS_ERROR_GSS(gss_rc, minor_status);
1102 goto failed;
1105 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1106 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1107 ads->ldap.in.max_wrapped = max_msg_size;
1108 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1109 if (!ADS_ERR_OK(status)) {
1110 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1111 ads_errstr(status)));
1112 goto failed;
1114 /* make sure we don't free context_handle */
1115 context_handle = GSS_C_NO_CONTEXT;
1118 failed:
1120 if (context_handle != GSS_C_NO_CONTEXT)
1121 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1123 if(scred)
1124 ber_bvfree(scred);
1125 return status;
1128 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1130 ADS_STATUS status;
1131 struct ads_service_principal p;
1133 status = ads_generate_service_principal(ads, NULL, &p);
1134 if (!ADS_ERR_OK(status)) {
1135 return status;
1138 status = ads_sasl_gssapi_do_bind(ads, p.name);
1139 if (ADS_ERR_OK(status)) {
1140 ads_free_service_principal(&p);
1141 return status;
1144 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1145 "calling kinit\n", ads_errstr(status)));
1147 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1149 if (ADS_ERR_OK(status)) {
1150 status = ads_sasl_gssapi_do_bind(ads, p.name);
1153 ads_free_service_principal(&p);
1155 return status;
1158 #endif /* HAVE_KRB5 */
1160 /* mapping between SASL mechanisms and functions */
1161 static struct {
1162 const char *name;
1163 ADS_STATUS (*fn)(ADS_STRUCT *);
1164 } sasl_mechanisms[] = {
1165 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1166 #ifdef HAVE_KRB5
1167 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1168 #endif
1169 {NULL, NULL}
1172 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1174 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1175 char **values;
1176 ADS_STATUS status;
1177 int i, j;
1178 LDAPMessage *res;
1180 /* get a list of supported SASL mechanisms */
1181 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1182 if (!ADS_ERR_OK(status)) return status;
1184 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1186 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1187 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1188 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1189 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1190 } else {
1191 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1194 /* try our supported mechanisms in order */
1195 for (i=0;sasl_mechanisms[i].name;i++) {
1196 /* see if the server supports it */
1197 for (j=0;values && values[j];j++) {
1198 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1199 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1200 retry:
1201 status = sasl_mechanisms[i].fn(ads);
1202 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1203 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1204 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1206 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1207 "retrying with signing enabled\n"));
1208 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1209 goto retry;
1211 ldap_value_free(values);
1212 ldap_msgfree(res);
1213 return status;
1218 ldap_value_free(values);
1219 ldap_msgfree(res);
1220 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1223 #endif /* HAVE_LDAP */