Always pass a TALLOC_CTX to str_list_make and str_list_copy
[Samba/gbeck.git] / source3 / libads / sasl.c
blob798d0b4365a45e0119b43f953070b9677e4b415c
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"
22 #ifdef HAVE_LDAP
24 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
26 struct ntlmssp_state *ntlmssp_state =
27 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
28 ADS_STATUS status;
29 NTSTATUS nt_status;
30 DATA_BLOB sig;
31 uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
33 /* copy the data to the right location */
34 memcpy(dptr, buf, len);
36 /* create the signature and may encrypt the data */
37 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
38 nt_status = ntlmssp_seal_packet(ntlmssp_state,
39 dptr, len,
40 dptr, len,
41 &sig);
42 } else {
43 nt_status = ntlmssp_sign_packet(ntlmssp_state,
44 dptr, len,
45 dptr, len,
46 &sig);
48 status = ADS_ERROR_NT(nt_status);
49 if (!ADS_ERR_OK(status)) return status;
51 /* copy the signature to the right location */
52 memcpy(ads->ldap.out.buf + 4,
53 sig.data, NTLMSSP_SIG_SIZE);
55 data_blob_free(&sig);
57 /* set how many bytes must be written to the underlying socket */
58 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
60 return ADS_SUCCESS;
63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
65 struct ntlmssp_state *ntlmssp_state =
66 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
67 ADS_STATUS status;
68 NTSTATUS nt_status;
69 DATA_BLOB sig;
70 uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
71 uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
73 /* wrap the signature into a DATA_BLOB */
74 sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
76 /* verify the signature and maybe decrypt the data */
77 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
78 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
79 dptr, dlen,
80 dptr, dlen,
81 &sig);
82 } else {
83 nt_status = ntlmssp_check_packet(ntlmssp_state,
84 dptr, dlen,
85 dptr, dlen,
86 &sig);
88 status = ADS_ERROR_NT(nt_status);
89 if (!ADS_ERR_OK(status)) return status;
91 /* set the amount of bytes for the upper layer and set the ofs to the data */
92 ads->ldap.in.left = dlen;
93 ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE;
95 return ADS_SUCCESS;
98 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
100 struct ntlmssp_state *ntlmssp_state =
101 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
103 ntlmssp_end(&ntlmssp_state);
105 ads->ldap.wrap_ops = NULL;
106 ads->ldap.wrap_private_data = NULL;
109 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
110 .name = "ntlmssp",
111 .wrap = ads_sasl_ntlmssp_wrap,
112 .unwrap = ads_sasl_ntlmssp_unwrap,
113 .disconnect = ads_sasl_ntlmssp_disconnect
117 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
118 we fit on one socket??)
120 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
122 DATA_BLOB msg1 = data_blob_null;
123 DATA_BLOB blob = data_blob_null;
124 DATA_BLOB blob_in = data_blob_null;
125 DATA_BLOB blob_out = data_blob_null;
126 struct berval cred, *scred = NULL;
127 int rc;
128 NTSTATUS nt_status;
129 ADS_STATUS status;
130 int turn = 1;
131 uint32 features = 0;
133 struct ntlmssp_state *ntlmssp_state;
135 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
136 return ADS_ERROR_NT(nt_status);
138 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
140 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
141 return ADS_ERROR_NT(nt_status);
143 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
144 return ADS_ERROR_NT(nt_status);
146 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
147 return ADS_ERROR_NT(nt_status);
150 switch (ads->ldap.wrap_type) {
151 case ADS_SASLWRAP_TYPE_SEAL:
152 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
153 break;
154 case ADS_SASLWRAP_TYPE_SIGN:
155 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
156 features = NTLMSSP_FEATURE_SIGN;
157 } else {
159 * windows servers are broken with sign only,
160 * so we need to use seal here too
162 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
163 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
165 break;
166 case ADS_SASLWRAP_TYPE_PLAIN:
167 break;
170 ntlmssp_want_feature(ntlmssp_state, features);
172 blob_in = data_blob_null;
174 do {
175 nt_status = ntlmssp_update(ntlmssp_state,
176 blob_in, &blob_out);
177 data_blob_free(&blob_in);
178 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
179 || NT_STATUS_IS_OK(nt_status))
180 && blob_out.length) {
181 if (turn == 1) {
182 /* and wrap it in a SPNEGO wrapper */
183 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
184 } else {
185 /* wrap it in SPNEGO */
186 msg1 = spnego_gen_auth(blob_out);
189 data_blob_free(&blob_out);
191 cred.bv_val = (char *)msg1.data;
192 cred.bv_len = msg1.length;
193 scred = NULL;
194 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
195 data_blob_free(&msg1);
196 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
197 if (scred) {
198 ber_bvfree(scred);
201 ntlmssp_end(&ntlmssp_state);
202 return ADS_ERROR(rc);
204 if (scred) {
205 blob = data_blob(scred->bv_val, scred->bv_len);
206 ber_bvfree(scred);
207 } else {
208 blob = data_blob_null;
211 } else {
213 ntlmssp_end(&ntlmssp_state);
214 data_blob_free(&blob_out);
215 return ADS_ERROR_NT(nt_status);
218 if ((turn == 1) &&
219 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
220 DATA_BLOB tmp_blob = data_blob_null;
221 /* the server might give us back two challenges */
222 if (!spnego_parse_challenge(blob, &blob_in,
223 &tmp_blob)) {
225 ntlmssp_end(&ntlmssp_state);
226 data_blob_free(&blob);
227 DEBUG(3,("Failed to parse challenges\n"));
228 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
230 data_blob_free(&tmp_blob);
231 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
232 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
233 &blob_in)) {
235 ntlmssp_end(&ntlmssp_state);
236 data_blob_free(&blob);
237 DEBUG(3,("Failed to parse auth response\n"));
238 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
241 data_blob_free(&blob);
242 data_blob_free(&blob_out);
243 turn++;
244 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
246 /* we have a reference conter on ntlmssp_state, if we are signing
247 then the state will be kept by the signing engine */
249 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
250 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
251 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
252 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
253 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
254 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
255 if (!ADS_ERR_OK(status)) {
256 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
257 ads_errstr(status)));
258 ntlmssp_end(&ntlmssp_state);
259 return status;
261 } else {
262 ntlmssp_end(&ntlmssp_state);
265 return ADS_ERROR(rc);
268 #ifdef HAVE_GSSAPI
269 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
271 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
272 ADS_STATUS status;
273 int gss_rc;
274 uint32 minor_status;
275 gss_buffer_desc unwrapped, wrapped;
276 int conf_req_flag, conf_state;
278 unwrapped.value = buf;
279 unwrapped.length = len;
281 /* for now request sign and seal */
282 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
284 gss_rc = gss_wrap(&minor_status, context_handle,
285 conf_req_flag, GSS_C_QOP_DEFAULT,
286 &unwrapped, &conf_state,
287 &wrapped);
288 status = ADS_ERROR_GSS(gss_rc, minor_status);
289 if (!ADS_ERR_OK(status)) return status;
291 if (conf_req_flag && conf_state == 0) {
292 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
295 if ((ads->ldap.out.size - 4) < wrapped.length) {
296 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
299 /* copy the wrapped blob to the right location */
300 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
302 /* set how many bytes must be written to the underlying socket */
303 ads->ldap.out.left = 4 + wrapped.length;
305 gss_release_buffer(&minor_status, &wrapped);
307 return ADS_SUCCESS;
310 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
312 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
313 ADS_STATUS status;
314 int gss_rc;
315 uint32 minor_status;
316 gss_buffer_desc unwrapped, wrapped;
317 int conf_state;
319 wrapped.value = ads->ldap.in.buf + 4;
320 wrapped.length = ads->ldap.in.ofs - 4;
322 gss_rc = gss_unwrap(&minor_status, context_handle,
323 &wrapped, &unwrapped,
324 &conf_state, GSS_C_QOP_DEFAULT);
325 status = ADS_ERROR_GSS(gss_rc, minor_status);
326 if (!ADS_ERR_OK(status)) return status;
328 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
329 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
332 if (wrapped.length < unwrapped.length) {
333 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
336 /* copy the wrapped blob to the right location */
337 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
339 /* set how many bytes must be written to the underlying socket */
340 ads->ldap.in.left = unwrapped.length;
341 ads->ldap.in.ofs = 4;
343 gss_release_buffer(&minor_status, &unwrapped);
345 return ADS_SUCCESS;
348 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
350 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
351 uint32 minor_status;
353 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
355 ads->ldap.wrap_ops = NULL;
356 ads->ldap.wrap_private_data = NULL;
359 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
360 .name = "gssapi",
361 .wrap = ads_sasl_gssapi_wrap,
362 .unwrap = ads_sasl_gssapi_unwrap,
363 .disconnect = ads_sasl_gssapi_disconnect
367 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
369 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
371 ADS_STATUS status;
372 bool ok;
373 uint32 minor_status;
374 int gss_rc, rc;
375 gss_OID_desc krb5_mech_type =
376 {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
377 gss_OID mech_type = &krb5_mech_type;
378 gss_OID actual_mech_type = GSS_C_NULL_OID;
379 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
380 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
381 gss_buffer_desc input_token, output_token;
382 uint32 req_flags, ret_flags;
383 uint32 req_tmp, ret_tmp;
384 DATA_BLOB unwrapped;
385 DATA_BLOB wrapped;
386 struct berval cred, *scred = NULL;
388 input_token.value = NULL;
389 input_token.length = 0;
391 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
392 switch (ads->ldap.wrap_type) {
393 case ADS_SASLWRAP_TYPE_SEAL:
394 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
395 break;
396 case ADS_SASLWRAP_TYPE_SIGN:
397 req_flags |= GSS_C_INTEG_FLAG;
398 break;
399 case ADS_SASLWRAP_TYPE_PLAIN:
400 break;
403 /* Note: here we explicit ask for the krb5 mech_type */
404 gss_rc = gss_init_sec_context(&minor_status,
405 GSS_C_NO_CREDENTIAL,
406 &context_handle,
407 serv_name,
408 mech_type,
409 req_flags,
411 NULL,
412 &input_token,
413 &actual_mech_type,
414 &output_token,
415 &ret_flags,
416 NULL);
417 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
418 status = ADS_ERROR_GSS(gss_rc, minor_status);
419 goto failed;
423 * As some gssapi krb5 mech implementations
424 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
425 * to req_flags internaly, it's not possible to
426 * use plain or signing only connection via
427 * the gssapi interface.
429 * Because of this we need to check it the ret_flags
430 * has more flags as req_flags and correct the value
431 * of ads->ldap.wrap_type.
433 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
434 * we need to give an error.
436 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
437 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
439 if (req_tmp == ret_tmp) {
440 /* everythings fine... */
442 } else if (req_flags & GSS_C_CONF_FLAG) {
444 * here we wanted sealing but didn't got it
445 * from the gssapi library
447 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
448 goto failed;
450 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
451 !(ret_flags & GSS_C_INTEG_FLAG)) {
453 * here we wanted siging but didn't got it
454 * from the gssapi library
456 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
457 goto failed;
459 } else if (ret_flags & GSS_C_CONF_FLAG) {
461 * here we didn't want sealing
462 * but the gssapi library forces it
463 * so correct the needed wrap_type if
464 * the caller didn't forced siging only
466 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
467 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
468 goto failed;
471 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
472 req_flags = ret_flags;
474 } else if (ret_flags & GSS_C_INTEG_FLAG) {
476 * here we didn't want signing
477 * but the gssapi library forces it
478 * so correct the needed wrap_type if
479 * the caller didn't forced plain
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_SIGN;
487 req_flags = ret_flags;
488 } else {
490 * This could (should?) not happen
492 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
493 goto failed;
497 /* and wrap that in a shiny SPNEGO wrapper */
498 unwrapped = data_blob_const(output_token.value, output_token.length);
499 wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
500 gss_release_buffer(&minor_status, &output_token);
501 if (unwrapped.length > wrapped.length) {
502 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
503 goto failed;
506 cred.bv_val = (char *)wrapped.data;
507 cred.bv_len = wrapped.length;
509 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
510 &scred);
511 data_blob_free(&wrapped);
512 if (rc != LDAP_SUCCESS) {
513 status = ADS_ERROR(rc);
514 goto failed;
517 if (scred) {
518 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
519 } else {
520 wrapped = data_blob_null;
523 ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
524 OID_KERBEROS5_OLD,
525 &unwrapped);
526 if (scred) ber_bvfree(scred);
527 if (!ok) {
528 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
529 goto failed;
532 input_token.value = unwrapped.data;
533 input_token.length = unwrapped.length;
536 * As we asked for mutal authentication
537 * we need to pass the servers response
538 * to gssapi
540 gss_rc = gss_init_sec_context(&minor_status,
541 GSS_C_NO_CREDENTIAL,
542 &context_handle,
543 serv_name,
544 mech_type,
545 req_flags,
547 NULL,
548 &input_token,
549 &actual_mech_type,
550 &output_token,
551 &ret_flags,
552 NULL);
553 data_blob_free(&unwrapped);
554 if (gss_rc) {
555 status = ADS_ERROR_GSS(gss_rc, minor_status);
556 goto failed;
559 gss_release_buffer(&minor_status, &output_token);
562 * If we the sign and seal options
563 * doesn't match after getting the response
564 * from the server, we don't want to use the connection
566 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
567 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
569 if (req_tmp != ret_tmp) {
570 /* everythings fine... */
571 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
572 goto failed;
575 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
576 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
578 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
579 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
580 GSS_C_QOP_DEFAULT,
581 max_msg_size, &ads->ldap.out.max_unwrapped);
582 if (gss_rc) {
583 status = ADS_ERROR_GSS(gss_rc, minor_status);
584 goto failed;
587 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
588 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
589 ads->ldap.in.max_wrapped = max_msg_size;
590 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
591 if (!ADS_ERR_OK(status)) {
592 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
593 ads_errstr(status)));
594 goto failed;
596 /* make sure we don't free context_handle */
597 context_handle = GSS_C_NO_CONTEXT;
600 failed:
601 if (context_handle != GSS_C_NO_CONTEXT)
602 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
603 return status;
606 #endif /* HAVE_GSSAPI */
608 #ifdef HAVE_KRB5
609 struct ads_service_principal {
610 char *string;
611 #ifdef HAVE_GSSAPI
612 gss_name_t name;
613 #endif
616 static void ads_free_service_principal(struct ads_service_principal *p)
618 SAFE_FREE(p->string);
620 #ifdef HAVE_GSSAPI
621 if (p->name) {
622 uint32 minor_status;
623 gss_release_name(&minor_status, &p->name);
625 #endif
626 ZERO_STRUCTP(p);
629 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
630 const char *given_principal,
631 struct ads_service_principal *p)
633 ADS_STATUS status;
634 #ifdef HAVE_GSSAPI
635 gss_buffer_desc input_name;
636 /* GSS_KRB5_NT_PRINCIPAL_NAME */
637 gss_OID_desc nt_principal =
638 {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
639 uint32 minor_status;
640 int gss_rc;
641 #endif
643 ZERO_STRUCTP(p);
645 /* I've seen a child Windows 2000 domain not send
646 the principal name back in the first round of
647 the SASL bind reply. So we guess based on server
648 name and realm. --jerry */
649 /* Also try best guess when we get the w2k8 ignore
650 principal back - gd */
652 if (!given_principal ||
653 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
655 status = ads_guess_service_principal(ads, &p->string);
656 if (!ADS_ERR_OK(status)) {
657 return status;
659 } else {
660 p->string = SMB_STRDUP(given_principal);
661 if (!p->string) {
662 return ADS_ERROR(LDAP_NO_MEMORY);
666 #ifdef HAVE_GSSAPI
667 input_name.value = p->string;
668 input_name.length = strlen(p->string);
670 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
671 if (gss_rc) {
672 ads_free_service_principal(p);
673 return ADS_ERROR_GSS(gss_rc, minor_status);
675 #endif
677 return ADS_SUCCESS;
681 perform a LDAP/SASL/SPNEGO/KRB5 bind
683 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
685 DATA_BLOB blob = data_blob_null;
686 struct berval cred, *scred = NULL;
687 DATA_BLOB session_key = data_blob_null;
688 int rc;
690 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
691 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
694 rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
695 &ads->auth.tgs_expire);
697 if (rc) {
698 return ADS_ERROR_KRB5(rc);
701 /* now send the auth packet and we should be done */
702 cred.bv_val = (char *)blob.data;
703 cred.bv_len = blob.length;
705 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
707 data_blob_free(&blob);
708 data_blob_free(&session_key);
709 if(scred)
710 ber_bvfree(scred);
712 return ADS_ERROR(rc);
715 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
716 struct ads_service_principal *p)
718 #ifdef HAVE_GSSAPI
720 * we only use the gsskrb5 based implementation
721 * when sasl sign or seal is requested.
723 * This has the following reasons:
724 * - it's likely that the gssapi krb5 mech implementation
725 * doesn't support to negotiate plain connections
726 * - the ads_sasl_spnego_rawkrb5_bind is more robust
727 * against clock skew errors
729 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
730 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
732 #endif
733 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
735 #endif /* HAVE_KRB5 */
738 this performs a SASL/SPNEGO bind
740 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
742 struct berval *scred=NULL;
743 int rc, i;
744 ADS_STATUS status;
745 DATA_BLOB blob;
746 char *given_principal = NULL;
747 char *OIDs[ASN1_MAX_OIDS];
748 #ifdef HAVE_KRB5
749 bool got_kerberos_mechanism = False;
750 #endif
752 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
754 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
755 status = ADS_ERROR(rc);
756 goto failed;
759 blob = data_blob(scred->bv_val, scred->bv_len);
761 ber_bvfree(scred);
763 #if 0
764 file_save("sasl_spnego.dat", blob.data, blob.length);
765 #endif
767 /* the server sent us the first part of the SPNEGO exchange in the negprot
768 reply */
769 if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
770 data_blob_free(&blob);
771 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
772 goto failed;
774 data_blob_free(&blob);
776 /* make sure the server understands kerberos */
777 for (i=0;OIDs[i];i++) {
778 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
779 #ifdef HAVE_KRB5
780 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
781 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
782 got_kerberos_mechanism = True;
784 #endif
785 free(OIDs[i]);
787 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
789 #ifdef HAVE_KRB5
790 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
791 got_kerberos_mechanism)
793 struct ads_service_principal p;
795 status = ads_generate_service_principal(ads, given_principal, &p);
796 SAFE_FREE(given_principal);
797 if (!ADS_ERR_OK(status)) {
798 return status;
801 status = ads_sasl_spnego_krb5_bind(ads, &p);
802 if (ADS_ERR_OK(status)) {
803 ads_free_service_principal(&p);
804 return status;
807 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
808 "calling kinit\n", ads_errstr(status)));
810 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
812 if (ADS_ERR_OK(status)) {
813 status = ads_sasl_spnego_krb5_bind(ads, &p);
814 if (!ADS_ERR_OK(status)) {
815 DEBUG(0,("kinit succeeded but "
816 "ads_sasl_spnego_krb5_bind failed: %s\n",
817 ads_errstr(status)));
821 ads_free_service_principal(&p);
823 /* only fallback to NTLMSSP if allowed */
824 if (ADS_ERR_OK(status) ||
825 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
826 return status;
828 } else
829 #endif
831 SAFE_FREE(given_principal);
834 /* lets do NTLMSSP ... this has the big advantage that we don't need
835 to sync clocks, and we don't rely on special versions of the krb5
836 library for HMAC_MD4 encryption */
837 return ads_sasl_spnego_ntlmssp_bind(ads);
839 failed:
840 return status;
843 #ifdef HAVE_GSSAPI
844 #define MAX_GSS_PASSES 3
846 /* this performs a SASL/gssapi bind
847 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
848 is very dependent on correctly configured DNS whereas
849 this routine is much less fragile
850 see RFC2078 and RFC2222 for details
852 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
854 uint32 minor_status;
855 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
856 gss_OID mech_type = GSS_C_NULL_OID;
857 gss_buffer_desc output_token, input_token;
858 uint32 req_flags, ret_flags;
859 int conf_state;
860 struct berval cred;
861 struct berval *scred = NULL;
862 int i=0;
863 int gss_rc, rc;
864 uint8 *p;
865 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
866 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
867 ADS_STATUS status;
869 input_token.value = NULL;
870 input_token.length = 0;
873 * Note: here we always ask the gssapi for sign and seal
874 * as this is negotiated later after the mutal
875 * authentication
877 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
879 for (i=0; i < MAX_GSS_PASSES; i++) {
880 gss_rc = gss_init_sec_context(&minor_status,
881 GSS_C_NO_CREDENTIAL,
882 &context_handle,
883 serv_name,
884 mech_type,
885 req_flags,
887 NULL,
888 &input_token,
889 NULL,
890 &output_token,
891 &ret_flags,
892 NULL);
893 if (scred) {
894 ber_bvfree(scred);
895 scred = NULL;
897 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
898 status = ADS_ERROR_GSS(gss_rc, minor_status);
899 goto failed;
902 cred.bv_val = (char *)output_token.value;
903 cred.bv_len = output_token.length;
905 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
906 &scred);
907 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
908 status = ADS_ERROR(rc);
909 goto failed;
912 if (output_token.value) {
913 gss_release_buffer(&minor_status, &output_token);
916 if (scred) {
917 input_token.value = scred->bv_val;
918 input_token.length = scred->bv_len;
919 } else {
920 input_token.value = NULL;
921 input_token.length = 0;
924 if (gss_rc == 0) break;
927 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
928 &conf_state,NULL);
929 if (scred) {
930 ber_bvfree(scred);
931 scred = NULL;
933 if (gss_rc) {
934 status = ADS_ERROR_GSS(gss_rc, minor_status);
935 goto failed;
938 p = (uint8 *)output_token.value;
940 #if 0
941 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
942 #endif
944 if (p) {
945 wrap_type = CVAL(p,0);
946 SCVAL(p,0,0);
947 max_msg_size = RIVAL(p,0);
950 gss_release_buffer(&minor_status, &output_token);
952 if (!(wrap_type & ads->ldap.wrap_type)) {
954 * the server doesn't supports the wrap
955 * type we want :-(
957 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
958 ads->ldap.wrap_type, wrap_type));
959 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
960 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
961 goto failed;
964 /* 0x58 is the minimum windows accepts */
965 if (max_msg_size < 0x58) {
966 max_msg_size = 0x58;
969 output_token.length = 4;
970 output_token.value = SMB_MALLOC(output_token.length);
971 p = (uint8 *)output_token.value;
973 RSIVAL(p,0,max_msg_size);
974 SCVAL(p,0,ads->ldap.wrap_type);
977 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
978 * but using ads->config.bind_path is the wrong! It should be
979 * the DN of the user object!
981 * w2k3 gives an error when we send an incorrect DN, but sending nothing
982 * is ok and matches the information flow used in GSS-SPNEGO.
985 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
986 &output_token, &conf_state,
987 &input_token);
988 if (gss_rc) {
989 status = ADS_ERROR_GSS(gss_rc, minor_status);
990 goto failed;
993 free(output_token.value);
995 cred.bv_val = (char *)input_token.value;
996 cred.bv_len = input_token.length;
998 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
999 &scred);
1000 gss_release_buffer(&minor_status, &input_token);
1001 status = ADS_ERROR(rc);
1002 if (!ADS_ERR_OK(status)) {
1003 goto failed;
1006 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1007 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1008 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1009 GSS_C_QOP_DEFAULT,
1010 max_msg_size, &ads->ldap.out.max_unwrapped);
1011 if (gss_rc) {
1012 status = ADS_ERROR_GSS(gss_rc, minor_status);
1013 goto failed;
1016 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1017 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1018 ads->ldap.in.max_wrapped = max_msg_size;
1019 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1020 if (!ADS_ERR_OK(status)) {
1021 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1022 ads_errstr(status)));
1023 goto failed;
1025 /* make sure we don't free context_handle */
1026 context_handle = GSS_C_NO_CONTEXT;
1029 failed:
1031 if (context_handle != GSS_C_NO_CONTEXT)
1032 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1034 if(scred)
1035 ber_bvfree(scred);
1036 return status;
1039 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1041 ADS_STATUS status;
1042 struct ads_service_principal p;
1044 status = ads_generate_service_principal(ads, NULL, &p);
1045 if (!ADS_ERR_OK(status)) {
1046 return status;
1049 status = ads_sasl_gssapi_do_bind(ads, p.name);
1050 if (ADS_ERR_OK(status)) {
1051 ads_free_service_principal(&p);
1052 return status;
1055 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1056 "calling kinit\n", ads_errstr(status)));
1058 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1060 if (ADS_ERR_OK(status)) {
1061 status = ads_sasl_gssapi_do_bind(ads, p.name);
1064 ads_free_service_principal(&p);
1066 return status;
1069 #endif /* HAVE_GSSAPI */
1071 /* mapping between SASL mechanisms and functions */
1072 static struct {
1073 const char *name;
1074 ADS_STATUS (*fn)(ADS_STRUCT *);
1075 } sasl_mechanisms[] = {
1076 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1077 #ifdef HAVE_GSSAPI
1078 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1079 #endif
1080 {NULL, NULL}
1083 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1085 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1086 char **values;
1087 ADS_STATUS status;
1088 int i, j;
1089 LDAPMessage *res;
1091 /* get a list of supported SASL mechanisms */
1092 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1093 if (!ADS_ERR_OK(status)) return status;
1095 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1097 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1098 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1099 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1100 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1101 } else {
1102 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1105 /* try our supported mechanisms in order */
1106 for (i=0;sasl_mechanisms[i].name;i++) {
1107 /* see if the server supports it */
1108 for (j=0;values && values[j];j++) {
1109 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1110 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1111 status = sasl_mechanisms[i].fn(ads);
1112 ldap_value_free(values);
1113 ldap_msgfree(res);
1114 return status;
1119 ldap_value_free(values);
1120 ldap_msgfree(res);
1121 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1124 #endif /* HAVE_LDAP */