s3:torture: fix run_uid_regression_test
[Samba/gebeck_regimport.git] / source3 / libads / sasl.c
blob051fc961d9bc50a31a4989eb43e0fe94b120b46e
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 "../libcli/auth/ntlmssp.h"
23 #include "ads.h"
24 #include "smb_krb5.h"
26 #ifdef HAVE_LDAP
28 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
30 struct ntlmssp_state *ntlmssp_state =
31 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
32 ADS_STATUS status;
33 NTSTATUS nt_status;
34 DATA_BLOB sig;
35 TALLOC_CTX *frame;
36 uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
38 frame = talloc_stackframe();
39 /* copy the data to the right location */
40 memcpy(dptr, buf, len);
42 /* create the signature and may encrypt the data */
43 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
44 nt_status = ntlmssp_seal_packet(ntlmssp_state,
45 frame,
46 dptr, len,
47 dptr, len,
48 &sig);
49 } else {
50 nt_status = ntlmssp_sign_packet(ntlmssp_state,
51 frame,
52 dptr, len,
53 dptr, len,
54 &sig);
56 status = ADS_ERROR_NT(nt_status);
57 if (!ADS_ERR_OK(status)) return status;
59 /* copy the signature to the right location */
60 memcpy(ads->ldap.out.buf + 4,
61 sig.data, NTLMSSP_SIG_SIZE);
63 TALLOC_FREE(frame);
65 /* set how many bytes must be written to the underlying socket */
66 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
68 return ADS_SUCCESS;
71 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
73 struct ntlmssp_state *ntlmssp_state =
74 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
75 ADS_STATUS status;
76 NTSTATUS nt_status;
77 DATA_BLOB sig;
78 uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
79 uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
81 /* wrap the signature into a DATA_BLOB */
82 sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
84 /* verify the signature and maybe decrypt the data */
85 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
86 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
87 dptr, dlen,
88 dptr, dlen,
89 &sig);
90 } else {
91 nt_status = ntlmssp_check_packet(ntlmssp_state,
92 dptr, dlen,
93 dptr, dlen,
94 &sig);
96 status = ADS_ERROR_NT(nt_status);
97 if (!ADS_ERR_OK(status)) return status;
99 /* set the amount of bytes for the upper layer and set the ofs to the data */
100 ads->ldap.in.left = dlen;
101 ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE;
103 return ADS_SUCCESS;
106 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
108 struct ntlmssp_state *ntlmssp_state =
109 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
111 TALLOC_FREE(ntlmssp_state);
113 ads->ldap.wrap_ops = NULL;
114 ads->ldap.wrap_private_data = NULL;
117 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
118 .name = "ntlmssp",
119 .wrap = ads_sasl_ntlmssp_wrap,
120 .unwrap = ads_sasl_ntlmssp_unwrap,
121 .disconnect = ads_sasl_ntlmssp_disconnect
125 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
126 we fit on one socket??)
128 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
130 DATA_BLOB msg1 = data_blob_null;
131 DATA_BLOB blob = data_blob_null;
132 DATA_BLOB blob_in = data_blob_null;
133 DATA_BLOB blob_out = data_blob_null;
134 struct berval cred, *scred = NULL;
135 int rc;
136 NTSTATUS nt_status;
137 ADS_STATUS status;
138 int turn = 1;
139 uint32 features = 0;
141 struct ntlmssp_state *ntlmssp_state;
143 nt_status = ntlmssp_client_start(NULL,
144 global_myname(),
145 lp_workgroup(),
146 lp_client_ntlmv2_auth(),
147 &ntlmssp_state);
148 if (!NT_STATUS_IS_OK(nt_status)) {
149 return ADS_ERROR_NT(nt_status);
151 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
153 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
154 return ADS_ERROR_NT(nt_status);
156 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
157 return ADS_ERROR_NT(nt_status);
159 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
160 return ADS_ERROR_NT(nt_status);
163 switch (ads->ldap.wrap_type) {
164 case ADS_SASLWRAP_TYPE_SEAL:
165 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
166 break;
167 case ADS_SASLWRAP_TYPE_SIGN:
168 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
169 features = NTLMSSP_FEATURE_SIGN;
170 } else {
172 * windows servers are broken with sign only,
173 * so we need to use seal here too
175 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
176 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
178 break;
179 case ADS_SASLWRAP_TYPE_PLAIN:
180 break;
183 ntlmssp_want_feature(ntlmssp_state, features);
185 blob_in = data_blob_null;
187 do {
188 nt_status = ntlmssp_update(ntlmssp_state,
189 blob_in, &blob_out);
190 data_blob_free(&blob_in);
191 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
192 || NT_STATUS_IS_OK(nt_status))
193 && blob_out.length) {
194 if (turn == 1) {
195 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
196 /* and wrap it in a SPNEGO wrapper */
197 msg1 = spnego_gen_negTokenInit(talloc_tos(),
198 OIDs_ntlm, &blob_out, NULL);
199 } else {
200 /* wrap it in SPNEGO */
201 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
204 data_blob_free(&blob_out);
206 cred.bv_val = (char *)msg1.data;
207 cred.bv_len = msg1.length;
208 scred = NULL;
209 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
210 data_blob_free(&msg1);
211 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
212 if (scred) {
213 ber_bvfree(scred);
216 TALLOC_FREE(ntlmssp_state);
217 return ADS_ERROR(rc);
219 if (scred) {
220 blob = data_blob(scred->bv_val, scred->bv_len);
221 ber_bvfree(scred);
222 } else {
223 blob = data_blob_null;
226 } else {
228 TALLOC_FREE(ntlmssp_state);
229 data_blob_free(&blob_out);
230 return ADS_ERROR_NT(nt_status);
233 if ((turn == 1) &&
234 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
235 DATA_BLOB tmp_blob = data_blob_null;
236 /* the server might give us back two challenges */
237 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
238 &tmp_blob)) {
240 TALLOC_FREE(ntlmssp_state);
241 data_blob_free(&blob);
242 DEBUG(3,("Failed to parse challenges\n"));
243 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
245 data_blob_free(&tmp_blob);
246 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
247 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
248 &blob_in)) {
250 TALLOC_FREE(ntlmssp_state);
251 data_blob_free(&blob);
252 DEBUG(3,("Failed to parse auth response\n"));
253 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
256 data_blob_free(&blob);
257 data_blob_free(&blob_out);
258 turn++;
259 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
261 /* we have a reference conter on ntlmssp_state, if we are signing
262 then the state will be kept by the signing engine */
264 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
265 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
266 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
267 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
268 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
269 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
270 if (!ADS_ERR_OK(status)) {
271 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
272 ads_errstr(status)));
273 TALLOC_FREE(ntlmssp_state);
274 return status;
276 } else {
277 TALLOC_FREE(ntlmssp_state);
280 return ADS_ERROR(rc);
283 #ifdef HAVE_GSSAPI
284 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
286 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
287 ADS_STATUS status;
288 int gss_rc;
289 uint32 minor_status;
290 gss_buffer_desc unwrapped, wrapped;
291 int conf_req_flag, conf_state;
293 unwrapped.value = buf;
294 unwrapped.length = len;
296 /* for now request sign and seal */
297 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
299 gss_rc = gss_wrap(&minor_status, context_handle,
300 conf_req_flag, GSS_C_QOP_DEFAULT,
301 &unwrapped, &conf_state,
302 &wrapped);
303 status = ADS_ERROR_GSS(gss_rc, minor_status);
304 if (!ADS_ERR_OK(status)) return status;
306 if (conf_req_flag && conf_state == 0) {
307 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
310 if ((ads->ldap.out.size - 4) < wrapped.length) {
311 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
314 /* copy the wrapped blob to the right location */
315 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
317 /* set how many bytes must be written to the underlying socket */
318 ads->ldap.out.left = 4 + wrapped.length;
320 gss_release_buffer(&minor_status, &wrapped);
322 return ADS_SUCCESS;
325 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
327 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
328 ADS_STATUS status;
329 int gss_rc;
330 uint32 minor_status;
331 gss_buffer_desc unwrapped, wrapped;
332 int conf_state;
334 wrapped.value = ads->ldap.in.buf + 4;
335 wrapped.length = ads->ldap.in.ofs - 4;
337 gss_rc = gss_unwrap(&minor_status, context_handle,
338 &wrapped, &unwrapped,
339 &conf_state, GSS_C_QOP_DEFAULT);
340 status = ADS_ERROR_GSS(gss_rc, minor_status);
341 if (!ADS_ERR_OK(status)) return status;
343 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
344 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
347 if (wrapped.length < unwrapped.length) {
348 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
351 /* copy the wrapped blob to the right location */
352 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
354 /* set how many bytes must be written to the underlying socket */
355 ads->ldap.in.left = unwrapped.length;
356 ads->ldap.in.ofs = 4;
358 gss_release_buffer(&minor_status, &unwrapped);
360 return ADS_SUCCESS;
363 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
365 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
366 uint32 minor_status;
368 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
370 ads->ldap.wrap_ops = NULL;
371 ads->ldap.wrap_private_data = NULL;
374 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
375 .name = "gssapi",
376 .wrap = ads_sasl_gssapi_wrap,
377 .unwrap = ads_sasl_gssapi_unwrap,
378 .disconnect = ads_sasl_gssapi_disconnect
382 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
384 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
386 ADS_STATUS status;
387 bool ok;
388 uint32 minor_status;
389 int gss_rc, rc;
390 gss_OID_desc krb5_mech_type =
391 {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
392 gss_OID mech_type = &krb5_mech_type;
393 gss_OID actual_mech_type = GSS_C_NULL_OID;
394 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
395 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
396 gss_buffer_desc input_token, output_token;
397 uint32 req_flags, ret_flags;
398 uint32 req_tmp, ret_tmp;
399 DATA_BLOB unwrapped;
400 DATA_BLOB wrapped;
401 struct berval cred, *scred = NULL;
403 input_token.value = NULL;
404 input_token.length = 0;
406 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
407 switch (ads->ldap.wrap_type) {
408 case ADS_SASLWRAP_TYPE_SEAL:
409 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
410 break;
411 case ADS_SASLWRAP_TYPE_SIGN:
412 req_flags |= GSS_C_INTEG_FLAG;
413 break;
414 case ADS_SASLWRAP_TYPE_PLAIN:
415 break;
418 /* Note: here we explicit ask for the krb5 mech_type */
419 gss_rc = gss_init_sec_context(&minor_status,
420 GSS_C_NO_CREDENTIAL,
421 &context_handle,
422 serv_name,
423 mech_type,
424 req_flags,
426 NULL,
427 &input_token,
428 &actual_mech_type,
429 &output_token,
430 &ret_flags,
431 NULL);
432 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
433 status = ADS_ERROR_GSS(gss_rc, minor_status);
434 goto failed;
438 * As some gssapi krb5 mech implementations
439 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
440 * to req_flags internaly, it's not possible to
441 * use plain or signing only connection via
442 * the gssapi interface.
444 * Because of this we need to check it the ret_flags
445 * has more flags as req_flags and correct the value
446 * of ads->ldap.wrap_type.
448 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
449 * we need to give an error.
451 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
452 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
454 if (req_tmp == ret_tmp) {
455 /* everythings fine... */
457 } else if (req_flags & GSS_C_CONF_FLAG) {
459 * here we wanted sealing but didn't got it
460 * from the gssapi library
462 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
463 goto failed;
465 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
466 !(ret_flags & GSS_C_INTEG_FLAG)) {
468 * here we wanted siging but didn't got it
469 * from the gssapi library
471 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
472 goto failed;
474 } else if (ret_flags & GSS_C_CONF_FLAG) {
476 * here we didn't want sealing
477 * but the gssapi library forces it
478 * so correct the needed wrap_type if
479 * the caller didn't forced siging only
481 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
482 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
483 goto failed;
486 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
487 req_flags = ret_flags;
489 } else if (ret_flags & GSS_C_INTEG_FLAG) {
491 * here we didn't want signing
492 * but the gssapi library forces it
493 * so correct the needed wrap_type if
494 * the caller didn't forced plain
496 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
497 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
498 goto failed;
501 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
502 req_flags = ret_flags;
503 } else {
505 * This could (should?) not happen
507 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
508 goto failed;
512 /* and wrap that in a shiny SPNEGO wrapper */
513 unwrapped = data_blob_const(output_token.value, output_token.length);
514 wrapped = spnego_gen_negTokenInit(talloc_tos(),
515 spnego_mechs, &unwrapped, NULL);
516 gss_release_buffer(&minor_status, &output_token);
517 if (unwrapped.length > wrapped.length) {
518 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
519 goto failed;
522 cred.bv_val = (char *)wrapped.data;
523 cred.bv_len = wrapped.length;
525 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
526 &scred);
527 data_blob_free(&wrapped);
528 if (rc != LDAP_SUCCESS) {
529 status = ADS_ERROR(rc);
530 goto failed;
533 if (scred) {
534 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
535 } else {
536 wrapped = data_blob_null;
539 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
540 OID_KERBEROS5_OLD,
541 &unwrapped);
542 if (scred) ber_bvfree(scred);
543 if (!ok) {
544 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
545 goto failed;
548 input_token.value = unwrapped.data;
549 input_token.length = unwrapped.length;
552 * As we asked for mutal authentication
553 * we need to pass the servers response
554 * to gssapi
556 gss_rc = gss_init_sec_context(&minor_status,
557 GSS_C_NO_CREDENTIAL,
558 &context_handle,
559 serv_name,
560 mech_type,
561 req_flags,
563 NULL,
564 &input_token,
565 &actual_mech_type,
566 &output_token,
567 &ret_flags,
568 NULL);
569 data_blob_free(&unwrapped);
570 if (gss_rc) {
571 status = ADS_ERROR_GSS(gss_rc, minor_status);
572 goto failed;
575 gss_release_buffer(&minor_status, &output_token);
578 * If we the sign and seal options
579 * doesn't match after getting the response
580 * from the server, we don't want to use the connection
582 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
583 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
585 if (req_tmp != ret_tmp) {
586 /* everythings fine... */
587 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
588 goto failed;
591 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
592 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
594 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
595 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
596 GSS_C_QOP_DEFAULT,
597 max_msg_size, &ads->ldap.out.max_unwrapped);
598 if (gss_rc) {
599 status = ADS_ERROR_GSS(gss_rc, minor_status);
600 goto failed;
603 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
604 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
605 ads->ldap.in.max_wrapped = max_msg_size;
606 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
607 if (!ADS_ERR_OK(status)) {
608 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
609 ads_errstr(status)));
610 goto failed;
612 /* make sure we don't free context_handle */
613 context_handle = GSS_C_NO_CONTEXT;
616 status = ADS_SUCCESS;
618 failed:
619 if (context_handle != GSS_C_NO_CONTEXT)
620 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
621 return status;
624 #endif /* HAVE_GSSAPI */
626 #ifdef HAVE_KRB5
627 struct ads_service_principal {
628 char *string;
629 #ifdef HAVE_GSSAPI
630 gss_name_t name;
631 #endif
634 static void ads_free_service_principal(struct ads_service_principal *p)
636 SAFE_FREE(p->string);
638 #ifdef HAVE_GSSAPI
639 if (p->name) {
640 uint32 minor_status;
641 gss_release_name(&minor_status, &p->name);
643 #endif
644 ZERO_STRUCTP(p);
647 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
648 const char *given_principal,
649 struct ads_service_principal *p)
651 ADS_STATUS status;
652 #ifdef HAVE_GSSAPI
653 gss_buffer_desc input_name;
654 /* GSS_KRB5_NT_PRINCIPAL_NAME */
655 gss_OID_desc nt_principal =
656 {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
657 uint32 minor_status;
658 int gss_rc;
659 #endif
661 ZERO_STRUCTP(p);
663 /* I've seen a child Windows 2000 domain not send
664 the principal name back in the first round of
665 the SASL bind reply. So we guess based on server
666 name and realm. --jerry */
667 /* Also try best guess when we get the w2k8 ignore
668 principal back - gd */
670 if (!given_principal ||
671 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
673 status = ads_guess_service_principal(ads, &p->string);
674 if (!ADS_ERR_OK(status)) {
675 return status;
677 } else {
678 p->string = SMB_STRDUP(given_principal);
679 if (!p->string) {
680 return ADS_ERROR(LDAP_NO_MEMORY);
684 #ifdef HAVE_GSSAPI
685 input_name.value = p->string;
686 input_name.length = strlen(p->string);
688 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
689 if (gss_rc) {
690 ads_free_service_principal(p);
691 return ADS_ERROR_GSS(gss_rc, minor_status);
693 #endif
695 return ADS_SUCCESS;
699 perform a LDAP/SASL/SPNEGO/KRB5 bind
701 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
703 DATA_BLOB blob = data_blob_null;
704 struct berval cred, *scred = NULL;
705 DATA_BLOB session_key = data_blob_null;
706 int rc;
708 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
709 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
712 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
713 ads->auth.time_offset, &blob, &session_key, 0,
714 &ads->auth.tgs_expire);
716 if (rc) {
717 return ADS_ERROR_KRB5(rc);
720 /* now send the auth packet and we should be done */
721 cred.bv_val = (char *)blob.data;
722 cred.bv_len = blob.length;
724 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
726 data_blob_free(&blob);
727 data_blob_free(&session_key);
728 if(scred)
729 ber_bvfree(scred);
731 return ADS_ERROR(rc);
734 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
735 struct ads_service_principal *p)
737 #ifdef HAVE_GSSAPI
739 * we only use the gsskrb5 based implementation
740 * when sasl sign or seal is requested.
742 * This has the following reasons:
743 * - it's likely that the gssapi krb5 mech implementation
744 * doesn't support to negotiate plain connections
745 * - the ads_sasl_spnego_rawkrb5_bind is more robust
746 * against clock skew errors
748 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
749 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
751 #endif
752 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
754 #endif /* HAVE_KRB5 */
757 this performs a SASL/SPNEGO bind
759 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
761 struct berval *scred=NULL;
762 int rc, i;
763 ADS_STATUS status;
764 DATA_BLOB blob;
765 char *given_principal = NULL;
766 char *OIDs[ASN1_MAX_OIDS];
767 #ifdef HAVE_KRB5
768 bool got_kerberos_mechanism = False;
769 #endif
771 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
773 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
774 status = ADS_ERROR(rc);
775 goto failed;
778 blob = data_blob(scred->bv_val, scred->bv_len);
780 ber_bvfree(scred);
782 #if 0
783 file_save("sasl_spnego.dat", blob.data, blob.length);
784 #endif
786 /* the server sent us the first part of the SPNEGO exchange in the negprot
787 reply */
788 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL)) {
789 data_blob_free(&blob);
790 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
791 goto failed;
793 data_blob_free(&blob);
795 /* make sure the server understands kerberos */
796 for (i=0;OIDs[i];i++) {
797 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
798 #ifdef HAVE_KRB5
799 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
800 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
801 got_kerberos_mechanism = True;
803 #endif
804 talloc_free(OIDs[i]);
806 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
808 #ifdef HAVE_KRB5
809 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
810 got_kerberos_mechanism)
812 struct ads_service_principal p;
814 status = ads_generate_service_principal(ads, given_principal, &p);
815 TALLOC_FREE(given_principal);
816 if (!ADS_ERR_OK(status)) {
817 return status;
820 status = ads_sasl_spnego_krb5_bind(ads, &p);
821 if (ADS_ERR_OK(status)) {
822 ads_free_service_principal(&p);
823 return status;
826 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
827 "calling kinit\n", ads_errstr(status)));
829 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
831 if (ADS_ERR_OK(status)) {
832 status = ads_sasl_spnego_krb5_bind(ads, &p);
833 if (!ADS_ERR_OK(status)) {
834 DEBUG(0,("kinit succeeded but "
835 "ads_sasl_spnego_krb5_bind failed: %s\n",
836 ads_errstr(status)));
840 ads_free_service_principal(&p);
842 /* only fallback to NTLMSSP if allowed */
843 if (ADS_ERR_OK(status) ||
844 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
845 return status;
847 } else
848 #endif
850 TALLOC_FREE(given_principal);
853 /* lets do NTLMSSP ... this has the big advantage that we don't need
854 to sync clocks, and we don't rely on special versions of the krb5
855 library for HMAC_MD4 encryption */
856 return ads_sasl_spnego_ntlmssp_bind(ads);
858 failed:
859 return status;
862 #ifdef HAVE_GSSAPI
863 #define MAX_GSS_PASSES 3
865 /* this performs a SASL/gssapi bind
866 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
867 is very dependent on correctly configured DNS whereas
868 this routine is much less fragile
869 see RFC2078 and RFC2222 for details
871 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
873 uint32 minor_status;
874 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
875 gss_OID mech_type = GSS_C_NULL_OID;
876 gss_buffer_desc output_token, input_token;
877 uint32 req_flags, ret_flags;
878 int conf_state;
879 struct berval cred;
880 struct berval *scred = NULL;
881 int i=0;
882 int gss_rc, rc;
883 uint8 *p;
884 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
885 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
886 ADS_STATUS status;
888 input_token.value = NULL;
889 input_token.length = 0;
892 * Note: here we always ask the gssapi for sign and seal
893 * as this is negotiated later after the mutal
894 * authentication
896 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
898 for (i=0; i < MAX_GSS_PASSES; i++) {
899 gss_rc = gss_init_sec_context(&minor_status,
900 GSS_C_NO_CREDENTIAL,
901 &context_handle,
902 serv_name,
903 mech_type,
904 req_flags,
906 NULL,
907 &input_token,
908 NULL,
909 &output_token,
910 &ret_flags,
911 NULL);
912 if (scred) {
913 ber_bvfree(scred);
914 scred = NULL;
916 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
917 status = ADS_ERROR_GSS(gss_rc, minor_status);
918 goto failed;
921 cred.bv_val = (char *)output_token.value;
922 cred.bv_len = output_token.length;
924 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
925 &scred);
926 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
927 status = ADS_ERROR(rc);
928 goto failed;
931 if (output_token.value) {
932 gss_release_buffer(&minor_status, &output_token);
935 if (scred) {
936 input_token.value = scred->bv_val;
937 input_token.length = scred->bv_len;
938 } else {
939 input_token.value = NULL;
940 input_token.length = 0;
943 if (gss_rc == 0) break;
946 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
947 &conf_state,NULL);
948 if (scred) {
949 ber_bvfree(scred);
950 scred = NULL;
952 if (gss_rc) {
953 status = ADS_ERROR_GSS(gss_rc, minor_status);
954 goto failed;
957 p = (uint8 *)output_token.value;
959 #if 0
960 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
961 #endif
963 if (p) {
964 wrap_type = CVAL(p,0);
965 SCVAL(p,0,0);
966 max_msg_size = RIVAL(p,0);
969 gss_release_buffer(&minor_status, &output_token);
971 if (!(wrap_type & ads->ldap.wrap_type)) {
973 * the server doesn't supports the wrap
974 * type we want :-(
976 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
977 ads->ldap.wrap_type, wrap_type));
978 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
979 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
980 goto failed;
983 /* 0x58 is the minimum windows accepts */
984 if (max_msg_size < 0x58) {
985 max_msg_size = 0x58;
988 output_token.length = 4;
989 output_token.value = SMB_MALLOC(output_token.length);
990 if (!output_token.value) {
991 output_token.length = 0;
992 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
993 goto failed;
995 p = (uint8 *)output_token.value;
997 RSIVAL(p,0,max_msg_size);
998 SCVAL(p,0,ads->ldap.wrap_type);
1001 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1002 * but using ads->config.bind_path is the wrong! It should be
1003 * the DN of the user object!
1005 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1006 * is ok and matches the information flow used in GSS-SPNEGO.
1009 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1010 &output_token, /* used as *input* here. */
1011 &conf_state,
1012 &input_token); /* Used as *output* here. */
1013 if (gss_rc) {
1014 status = ADS_ERROR_GSS(gss_rc, minor_status);
1015 output_token.length = 0;
1016 SAFE_FREE(output_token.value);
1017 goto failed;
1020 /* We've finished with output_token. */
1021 SAFE_FREE(output_token.value);
1022 output_token.length = 0;
1024 cred.bv_val = (char *)input_token.value;
1025 cred.bv_len = input_token.length;
1027 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1028 &scred);
1029 gss_release_buffer(&minor_status, &input_token);
1030 status = ADS_ERROR(rc);
1031 if (!ADS_ERR_OK(status)) {
1032 goto failed;
1035 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1036 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1037 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1038 GSS_C_QOP_DEFAULT,
1039 max_msg_size, &ads->ldap.out.max_unwrapped);
1040 if (gss_rc) {
1041 status = ADS_ERROR_GSS(gss_rc, minor_status);
1042 goto failed;
1045 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1046 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1047 ads->ldap.in.max_wrapped = max_msg_size;
1048 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1049 if (!ADS_ERR_OK(status)) {
1050 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1051 ads_errstr(status)));
1052 goto failed;
1054 /* make sure we don't free context_handle */
1055 context_handle = GSS_C_NO_CONTEXT;
1058 failed:
1060 if (context_handle != GSS_C_NO_CONTEXT)
1061 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1063 if(scred)
1064 ber_bvfree(scred);
1065 return status;
1068 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1070 ADS_STATUS status;
1071 struct ads_service_principal p;
1073 status = ads_generate_service_principal(ads, NULL, &p);
1074 if (!ADS_ERR_OK(status)) {
1075 return status;
1078 status = ads_sasl_gssapi_do_bind(ads, p.name);
1079 if (ADS_ERR_OK(status)) {
1080 ads_free_service_principal(&p);
1081 return status;
1084 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1085 "calling kinit\n", ads_errstr(status)));
1087 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1089 if (ADS_ERR_OK(status)) {
1090 status = ads_sasl_gssapi_do_bind(ads, p.name);
1093 ads_free_service_principal(&p);
1095 return status;
1098 #endif /* HAVE_GSSAPI */
1100 /* mapping between SASL mechanisms and functions */
1101 static struct {
1102 const char *name;
1103 ADS_STATUS (*fn)(ADS_STRUCT *);
1104 } sasl_mechanisms[] = {
1105 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1106 #ifdef HAVE_GSSAPI
1107 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1108 #endif
1109 {NULL, NULL}
1112 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1114 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1115 char **values;
1116 ADS_STATUS status;
1117 int i, j;
1118 LDAPMessage *res;
1120 /* get a list of supported SASL mechanisms */
1121 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1122 if (!ADS_ERR_OK(status)) return status;
1124 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1126 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1127 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1128 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1129 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1130 } else {
1131 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1134 /* try our supported mechanisms in order */
1135 for (i=0;sasl_mechanisms[i].name;i++) {
1136 /* see if the server supports it */
1137 for (j=0;values && values[j];j++) {
1138 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1139 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1140 retry:
1141 status = sasl_mechanisms[i].fn(ads);
1142 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1143 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1144 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1146 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1147 "retrying with signing enabled\n"));
1148 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1149 goto retry;
1151 ldap_value_free(values);
1152 ldap_msgfree(res);
1153 return status;
1158 ldap_value_free(values);
1159 ldap_msgfree(res);
1160 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1163 #endif /* HAVE_LDAP */