s4:librpc/rpc: let dcerpc_ship_next_request() use DCERPC_AUTH_PAD_ALIGNMENT define
[Samba.git] / source3 / libads / sasl.c
blob901e5bd3c97ab26fc36216f68afff8b27243c8d4
1 /*
2 Unix SMB/CIFS implementation.
3 ads sasl code
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "auth/gensec/gensec.h"
23 #include "auth_generic.h"
24 #include "ads.h"
25 #include "smb_krb5.h"
26 #include "system/gssapi.h"
27 #include "lib/param/loadparm.h"
29 #ifdef HAVE_LDAP
31 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
33 struct gensec_security *gensec_security =
34 talloc_get_type_abort(ads->ldap.wrap_private_data,
35 struct gensec_security);
36 NTSTATUS nt_status;
37 DATA_BLOB unwrapped, wrapped;
38 TALLOC_CTX *frame = talloc_stackframe();
40 unwrapped = data_blob_const(buf, len);
42 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
43 if (!NT_STATUS_IS_OK(nt_status)) {
44 TALLOC_FREE(frame);
45 return ADS_ERROR_NT(nt_status);
48 if ((ads->ldap.out.size - 4) < wrapped.length) {
49 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
52 /* copy the wrapped blob to the right location */
53 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
55 /* set how many bytes must be written to the underlying socket */
56 ads->ldap.out.left = 4 + wrapped.length;
58 TALLOC_FREE(frame);
60 return ADS_SUCCESS;
63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
65 struct gensec_security *gensec_security =
66 talloc_get_type_abort(ads->ldap.wrap_private_data,
67 struct gensec_security);
68 NTSTATUS nt_status;
69 DATA_BLOB unwrapped, wrapped;
70 TALLOC_CTX *frame = talloc_stackframe();
72 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
74 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
75 if (!NT_STATUS_IS_OK(nt_status)) {
76 TALLOC_FREE(frame);
77 return ADS_ERROR_NT(nt_status);
80 if (wrapped.length < unwrapped.length) {
81 TALLOC_FREE(frame);
82 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
85 /* copy the wrapped blob to the right location */
86 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
88 /* set how many bytes must be written to the underlying socket */
89 ads->ldap.in.left = unwrapped.length;
90 ads->ldap.in.ofs = 4;
92 TALLOC_FREE(frame);
94 return ADS_SUCCESS;
97 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
99 struct gensec_security *gensec_security =
100 talloc_get_type_abort(ads->ldap.wrap_private_data,
101 struct gensec_security);
103 TALLOC_FREE(gensec_security);
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;
132 struct auth_generic_state *auth_generic_state;
134 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
135 if (!NT_STATUS_IS_OK(nt_status)) {
136 return ADS_ERROR_NT(nt_status);
139 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
140 return ADS_ERROR_NT(nt_status);
142 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
143 return ADS_ERROR_NT(nt_status);
145 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
146 return ADS_ERROR_NT(nt_status);
149 switch (ads->ldap.wrap_type) {
150 case ADS_SASLWRAP_TYPE_SEAL:
151 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
152 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
153 break;
154 case ADS_SASLWRAP_TYPE_SIGN:
155 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
156 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
157 } else {
159 * windows servers are broken with sign only,
160 * so we need to use seal here too
162 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
163 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
164 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
166 break;
167 case ADS_SASLWRAP_TYPE_PLAIN:
168 break;
171 nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
172 if (!NT_STATUS_IS_OK(nt_status)) {
173 return ADS_ERROR_NT(nt_status);
176 blob_in = data_blob_null;
178 do {
179 nt_status = gensec_update(auth_generic_state->gensec_security,
180 talloc_tos(), NULL, blob_in, &blob_out);
181 data_blob_free(&blob_in);
182 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
183 || NT_STATUS_IS_OK(nt_status))
184 && blob_out.length) {
185 if (turn == 1) {
186 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
187 /* and wrap it in a SPNEGO wrapper */
188 msg1 = spnego_gen_negTokenInit(talloc_tos(),
189 OIDs_ntlm, &blob_out, NULL);
190 } else {
191 /* wrap it in SPNEGO */
192 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
195 data_blob_free(&blob_out);
197 cred.bv_val = (char *)msg1.data;
198 cred.bv_len = msg1.length;
199 scred = NULL;
200 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
201 data_blob_free(&msg1);
202 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
203 if (scred) {
204 ber_bvfree(scred);
207 TALLOC_FREE(auth_generic_state);
208 return ADS_ERROR(rc);
210 if (scred) {
211 blob = data_blob(scred->bv_val, scred->bv_len);
212 ber_bvfree(scred);
213 } else {
214 blob = data_blob_null;
217 } else {
219 TALLOC_FREE(auth_generic_state);
220 data_blob_free(&blob_out);
221 return ADS_ERROR_NT(nt_status);
224 if ((turn == 1) &&
225 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
226 DATA_BLOB tmp_blob = data_blob_null;
227 /* the server might give us back two challenges */
228 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
229 &tmp_blob)) {
231 TALLOC_FREE(auth_generic_state);
232 data_blob_free(&blob);
233 DEBUG(3,("Failed to parse challenges\n"));
234 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
236 data_blob_free(&tmp_blob);
237 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
238 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
239 &blob_in)) {
241 TALLOC_FREE(auth_generic_state);
242 data_blob_free(&blob);
243 DEBUG(3,("Failed to parse auth response\n"));
244 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
247 data_blob_free(&blob);
248 data_blob_free(&blob_out);
249 turn++;
250 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
252 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
253 uint32_t sig_size = gensec_sig_size(auth_generic_state->gensec_security, 0);
254 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - sig_size;
255 ads->ldap.out.sig_size = sig_size;
256 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
257 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
258 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
259 if (!ADS_ERR_OK(status)) {
260 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
261 ads_errstr(status)));
262 TALLOC_FREE(auth_generic_state);
263 return status;
265 /* Only keep the gensec_security element around long-term */
266 talloc_steal(NULL, auth_generic_state->gensec_security);
268 TALLOC_FREE(auth_generic_state);
270 return ADS_ERROR(rc);
273 #ifdef HAVE_KRB5
274 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
276 ADS_STATUS status;
277 krb5_context kctx;
278 krb5_error_code kerr;
279 krb5_ccache kccache = NULL;
280 uint32_t maj, min;
282 *cred = GSS_C_NO_CREDENTIAL;
284 if (!ads->auth.ccache_name) {
285 return ADS_SUCCESS;
288 kerr = krb5_init_context(&kctx);
289 if (kerr) {
290 return ADS_ERROR_KRB5(kerr);
293 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
294 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
295 if (kerr) {
296 status = ADS_ERROR_KRB5(kerr);
297 goto done;
300 maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
301 if (maj != GSS_S_COMPLETE) {
302 status = ADS_ERROR_GSS(maj, min);
303 goto done;
305 #else
306 /* We need to fallback to overriding the default creds.
307 * This operation is not thread safe as it changes the process
308 * environment variable, but we do not have any better option
309 * with older kerberos libraries */
311 const char *oldccname = NULL;
313 oldccname = getenv("KRB5CCNAME");
314 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
316 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
317 NULL, GSS_C_INITIATE, cred, NULL, NULL);
319 if (oldccname) {
320 setenv("KRB5CCNAME", oldccname, 1);
321 } else {
322 unsetenv("KRB5CCNAME");
325 if (maj != GSS_S_COMPLETE) {
326 status = ADS_ERROR_GSS(maj, min);
327 goto done;
330 #endif
332 status = ADS_SUCCESS;
334 done:
335 if (!ADS_ERR_OK(status) && kccache != NULL) {
336 krb5_cc_close(kctx, kccache);
338 krb5_free_context(kctx);
339 return status;
342 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
344 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
345 ADS_STATUS status;
346 int gss_rc;
347 uint32 minor_status;
348 gss_buffer_desc unwrapped, wrapped;
349 int conf_req_flag, conf_state;
351 unwrapped.value = buf;
352 unwrapped.length = len;
354 /* for now request sign and seal */
355 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
357 gss_rc = gss_wrap(&minor_status, context_handle,
358 conf_req_flag, GSS_C_QOP_DEFAULT,
359 &unwrapped, &conf_state,
360 &wrapped);
361 status = ADS_ERROR_GSS(gss_rc, minor_status);
362 if (!ADS_ERR_OK(status)) return status;
364 if (conf_req_flag && conf_state == 0) {
365 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
368 if ((ads->ldap.out.size - 4) < wrapped.length) {
369 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
372 /* copy the wrapped blob to the right location */
373 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
375 /* set how many bytes must be written to the underlying socket */
376 ads->ldap.out.left = 4 + wrapped.length;
378 gss_release_buffer(&minor_status, &wrapped);
380 return ADS_SUCCESS;
383 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
385 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
386 ADS_STATUS status;
387 int gss_rc;
388 uint32 minor_status;
389 gss_buffer_desc unwrapped, wrapped;
390 int conf_state;
392 wrapped.value = ads->ldap.in.buf + 4;
393 wrapped.length = ads->ldap.in.ofs - 4;
395 gss_rc = gss_unwrap(&minor_status, context_handle,
396 &wrapped, &unwrapped,
397 &conf_state, GSS_C_QOP_DEFAULT);
398 status = ADS_ERROR_GSS(gss_rc, minor_status);
399 if (!ADS_ERR_OK(status)) return status;
401 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
402 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
405 if (wrapped.length < unwrapped.length) {
406 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
409 /* copy the wrapped blob to the right location */
410 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
412 /* set how many bytes must be written to the underlying socket */
413 ads->ldap.in.left = unwrapped.length;
414 ads->ldap.in.ofs = 4;
416 gss_release_buffer(&minor_status, &unwrapped);
418 return ADS_SUCCESS;
421 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
423 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
424 uint32 minor_status;
426 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
428 ads->ldap.wrap_ops = NULL;
429 ads->ldap.wrap_private_data = NULL;
432 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
433 .name = "gssapi",
434 .wrap = ads_sasl_gssapi_wrap,
435 .unwrap = ads_sasl_gssapi_unwrap,
436 .disconnect = ads_sasl_gssapi_disconnect
440 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
442 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
444 ADS_STATUS status;
445 bool ok;
446 uint32 minor_status;
447 int gss_rc, rc;
448 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
449 gss_OID_desc krb5_mech_type =
450 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
451 gss_OID mech_type = &krb5_mech_type;
452 gss_OID actual_mech_type = GSS_C_NULL_OID;
453 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
454 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
455 gss_buffer_desc input_token, output_token;
456 uint32 req_flags, ret_flags;
457 uint32 req_tmp, ret_tmp;
458 DATA_BLOB unwrapped;
459 DATA_BLOB wrapped;
460 struct berval cred, *scred = NULL;
461 uint32_t context_validity = 0;
462 time_t context_endtime = 0;
464 status = ads_init_gssapi_cred(ads, &gss_cred);
465 if (!ADS_ERR_OK(status)) {
466 goto failed;
469 input_token.value = NULL;
470 input_token.length = 0;
472 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
473 switch (ads->ldap.wrap_type) {
474 case ADS_SASLWRAP_TYPE_SEAL:
475 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
476 break;
477 case ADS_SASLWRAP_TYPE_SIGN:
478 req_flags |= GSS_C_INTEG_FLAG;
479 break;
480 case ADS_SASLWRAP_TYPE_PLAIN:
481 break;
484 /* Note: here we explicit ask for the krb5 mech_type */
485 gss_rc = gss_init_sec_context(&minor_status,
486 gss_cred,
487 &context_handle,
488 serv_name,
489 mech_type,
490 req_flags,
492 NULL,
493 &input_token,
494 &actual_mech_type,
495 &output_token,
496 &ret_flags,
497 NULL);
498 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
499 status = ADS_ERROR_GSS(gss_rc, minor_status);
500 goto failed;
504 * As some gssapi krb5 mech implementations
505 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
506 * to req_flags internaly, it's not possible to
507 * use plain or signing only connection via
508 * the gssapi interface.
510 * Because of this we need to check it the ret_flags
511 * has more flags as req_flags and correct the value
512 * of ads->ldap.wrap_type.
514 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
515 * we need to give an error.
517 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
518 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
520 if (req_tmp == ret_tmp) {
521 /* everythings fine... */
523 } else if (req_flags & GSS_C_CONF_FLAG) {
525 * here we wanted sealing but didn't got it
526 * from the gssapi library
528 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
529 goto failed;
531 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
532 !(ret_flags & GSS_C_INTEG_FLAG)) {
534 * here we wanted siging but didn't got it
535 * from the gssapi library
537 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
538 goto failed;
540 } else if (ret_flags & GSS_C_CONF_FLAG) {
542 * here we didn't want sealing
543 * but the gssapi library forces it
544 * so correct the needed wrap_type if
545 * the caller didn't forced siging only
547 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
548 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
549 goto failed;
552 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
553 req_flags = ret_flags;
555 } else if (ret_flags & GSS_C_INTEG_FLAG) {
557 * here we didn't want signing
558 * but the gssapi library forces it
559 * so correct the needed wrap_type if
560 * the caller didn't forced plain
562 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
563 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
564 goto failed;
567 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
568 req_flags = ret_flags;
569 } else {
571 * This could (should?) not happen
573 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
574 goto failed;
578 /* and wrap that in a shiny SPNEGO wrapper */
579 unwrapped = data_blob_const(output_token.value, output_token.length);
580 wrapped = spnego_gen_negTokenInit(talloc_tos(),
581 spnego_mechs, &unwrapped, NULL);
582 gss_release_buffer(&minor_status, &output_token);
583 if (unwrapped.length > wrapped.length) {
584 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
585 goto failed;
588 cred.bv_val = (char *)wrapped.data;
589 cred.bv_len = wrapped.length;
591 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
592 &scred);
593 data_blob_free(&wrapped);
594 if (rc != LDAP_SUCCESS) {
595 status = ADS_ERROR(rc);
596 goto failed;
599 if (scred) {
600 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
601 } else {
602 wrapped = data_blob_null;
605 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
606 OID_KERBEROS5_OLD,
607 &unwrapped);
608 if (scred) ber_bvfree(scred);
609 if (!ok) {
610 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
611 goto failed;
614 input_token.value = unwrapped.data;
615 input_token.length = unwrapped.length;
618 * As we asked for mutal authentication
619 * we need to pass the servers response
620 * to gssapi
622 gss_rc = gss_init_sec_context(&minor_status,
623 gss_cred,
624 &context_handle,
625 serv_name,
626 mech_type,
627 req_flags,
629 NULL,
630 &input_token,
631 &actual_mech_type,
632 &output_token,
633 &ret_flags,
634 NULL);
635 data_blob_free(&unwrapped);
636 if (gss_rc) {
637 status = ADS_ERROR_GSS(gss_rc, minor_status);
638 goto failed;
641 gss_release_buffer(&minor_status, &output_token);
644 * If we the sign and seal options
645 * doesn't match after getting the response
646 * from the server, we don't want to use the connection
648 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
649 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
651 if (req_tmp != ret_tmp) {
652 /* everythings fine... */
653 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
654 goto failed;
657 gss_rc =
658 gss_context_time(&minor_status, context_handle, &context_validity);
659 if (gss_rc == GSS_S_COMPLETE) {
660 if (context_validity != 0) {
661 context_endtime = time(NULL) + context_validity;
662 DEBUG(10, ("context (service ticket) valid for "
663 "%u seconds\n",
664 context_validity));
665 } else {
666 DEBUG(10, ("context (service ticket) expired\n"));
668 } else {
669 DEBUG(1, ("gss_context_time failed (%d,%u) -"
670 " this will be a one-time context\n",
671 gss_rc, minor_status));
672 if (gss_rc == GSS_S_CONTEXT_EXPIRED) {
673 DEBUG(10, ("context (service ticket) expired\n"));
677 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
678 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
680 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
681 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
682 GSS_C_QOP_DEFAULT,
683 max_msg_size, &ads->ldap.out.max_unwrapped);
684 if (gss_rc) {
685 status = ADS_ERROR_GSS(gss_rc, minor_status);
686 goto failed;
689 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
690 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
691 ads->ldap.in.max_wrapped = max_msg_size;
692 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
693 if (!ADS_ERR_OK(status)) {
694 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
695 ads_errstr(status)));
696 goto failed;
698 /* make sure we don't free context_handle */
699 context_handle = GSS_C_NO_CONTEXT;
702 ads->auth.tgs_expire = context_endtime;
703 status = ADS_SUCCESS;
705 failed:
706 if (gss_cred != GSS_C_NO_CREDENTIAL)
707 gss_release_cred(&minor_status, &gss_cred);
708 if (context_handle != GSS_C_NO_CONTEXT)
709 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
710 return status;
713 #endif /* HAVE_KRB5 */
715 #ifdef HAVE_KRB5
716 struct ads_service_principal {
717 char *string;
718 #ifdef HAVE_KRB5
719 gss_name_t name;
720 #endif
723 static void ads_free_service_principal(struct ads_service_principal *p)
725 SAFE_FREE(p->string);
727 #ifdef HAVE_KRB5
728 if (p->name) {
729 uint32 minor_status;
730 gss_release_name(&minor_status, &p->name);
732 #endif
733 ZERO_STRUCTP(p);
737 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
738 char **returned_principal)
740 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
741 char *princ = NULL;
742 TALLOC_CTX *frame;
743 char *server = NULL;
744 char *realm = NULL;
745 int rc;
747 frame = talloc_stackframe();
748 if (frame == NULL) {
749 return ADS_ERROR(LDAP_NO_MEMORY);
752 if (ads->server.realm && ads->server.ldap_server) {
753 server = strlower_talloc(frame, ads->server.ldap_server);
754 if (server == NULL) {
755 goto out;
758 realm = strupper_talloc(frame, ads->server.realm);
759 if (realm == NULL) {
760 goto out;
764 * If we got a name which is bigger than a NetBIOS name,
765 * but isn't a FQDN, create one.
767 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
768 char *dnsdomain;
770 dnsdomain = strlower_talloc(frame, ads->server.realm);
771 if (dnsdomain == NULL) {
772 goto out;
775 server = talloc_asprintf(frame,
776 "%s.%s",
777 server, dnsdomain);
778 if (server == NULL) {
779 goto out;
782 } else if (ads->config.realm && ads->config.ldap_server_name) {
783 server = strlower_talloc(frame, ads->config.ldap_server_name);
784 if (server == NULL) {
785 goto out;
788 realm = strupper_talloc(frame, ads->config.realm);
789 if (realm == NULL) {
790 goto out;
794 * If we got a name which is bigger than a NetBIOS name,
795 * but isn't a FQDN, create one.
797 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
798 char *dnsdomain;
800 dnsdomain = strlower_talloc(frame, ads->server.realm);
801 if (dnsdomain == NULL) {
802 goto out;
805 server = talloc_asprintf(frame,
806 "%s.%s",
807 server, dnsdomain);
808 if (server == NULL) {
809 goto out;
814 if (server == NULL || realm == NULL) {
815 goto out;
818 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
819 if (rc == -1 || princ == NULL) {
820 status = ADS_ERROR(LDAP_PARAM_ERROR);
821 goto out;
824 *returned_principal = princ;
826 status = ADS_SUCCESS;
827 out:
828 TALLOC_FREE(frame);
829 return status;
832 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
833 const char *given_principal,
834 struct ads_service_principal *p)
836 ADS_STATUS status;
837 #ifdef HAVE_KRB5
838 gss_buffer_desc input_name;
839 /* GSS_KRB5_NT_PRINCIPAL_NAME */
840 gss_OID_desc nt_principal =
841 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
842 uint32 minor_status;
843 int gss_rc;
844 #endif
846 ZERO_STRUCTP(p);
848 /* I've seen a child Windows 2000 domain not send
849 the principal name back in the first round of
850 the SASL bind reply. So we guess based on server
851 name and realm. --jerry */
852 /* Also try best guess when we get the w2k8 ignore principal
853 back, or when we are configured to ignore it - gd,
854 abartlet */
856 if (!lp_client_use_spnego_principal() ||
857 !given_principal ||
858 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
860 status = ads_guess_service_principal(ads, &p->string);
861 if (!ADS_ERR_OK(status)) {
862 return status;
864 } else {
865 p->string = SMB_STRDUP(given_principal);
866 if (!p->string) {
867 return ADS_ERROR(LDAP_NO_MEMORY);
871 #ifdef HAVE_KRB5
872 input_name.value = p->string;
873 input_name.length = strlen(p->string);
875 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
876 if (gss_rc) {
877 ads_free_service_principal(p);
878 return ADS_ERROR_GSS(gss_rc, minor_status);
880 #endif
882 return ADS_SUCCESS;
886 perform a LDAP/SASL/SPNEGO/KRB5 bind
888 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
890 DATA_BLOB blob = data_blob_null;
891 struct berval cred, *scred = NULL;
892 DATA_BLOB session_key = data_blob_null;
893 int rc;
895 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
896 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
899 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
900 ads->auth.time_offset, &blob, &session_key, 0,
901 ads->auth.ccache_name,
902 &ads->auth.tgs_expire);
904 if (rc) {
905 return ADS_ERROR_KRB5(rc);
908 /* now send the auth packet and we should be done */
909 cred.bv_val = (char *)blob.data;
910 cred.bv_len = blob.length;
912 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
914 data_blob_free(&blob);
915 data_blob_free(&session_key);
916 if(scred)
917 ber_bvfree(scred);
919 return ADS_ERROR(rc);
922 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
923 struct ads_service_principal *p)
925 #ifdef HAVE_KRB5
927 * we only use the gsskrb5 based implementation
928 * when sasl sign or seal is requested.
930 * This has the following reasons:
931 * - it's likely that the gssapi krb5 mech implementation
932 * doesn't support to negotiate plain connections
933 * - the ads_sasl_spnego_rawkrb5_bind is more robust
934 * against clock skew errors
936 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
937 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
939 #endif
940 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
942 #endif /* HAVE_KRB5 */
945 this performs a SASL/SPNEGO bind
947 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
949 struct berval *scred=NULL;
950 int rc, i;
951 ADS_STATUS status;
952 DATA_BLOB blob;
953 char *given_principal = NULL;
954 char *OIDs[ASN1_MAX_OIDS];
955 #ifdef HAVE_KRB5
956 bool got_kerberos_mechanism = False;
957 #endif
959 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
961 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
962 status = ADS_ERROR(rc);
963 goto failed;
966 blob = data_blob(scred->bv_val, scred->bv_len);
968 ber_bvfree(scred);
970 #if 0
971 file_save("sasl_spnego.dat", blob.data, blob.length);
972 #endif
974 /* the server sent us the first part of the SPNEGO exchange in the negprot
975 reply */
976 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
977 OIDs[0] == NULL) {
978 data_blob_free(&blob);
979 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
980 goto failed;
982 data_blob_free(&blob);
984 /* make sure the server understands kerberos */
985 for (i=0;OIDs[i];i++) {
986 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
987 #ifdef HAVE_KRB5
988 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
989 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
990 got_kerberos_mechanism = True;
992 #endif
993 talloc_free(OIDs[i]);
995 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
997 #ifdef HAVE_KRB5
998 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
999 got_kerberos_mechanism)
1001 struct ads_service_principal p;
1003 status = ads_generate_service_principal(ads, given_principal, &p);
1004 TALLOC_FREE(given_principal);
1005 if (!ADS_ERR_OK(status)) {
1006 return status;
1009 status = ads_sasl_spnego_krb5_bind(ads, &p);
1010 if (ADS_ERR_OK(status)) {
1011 ads_free_service_principal(&p);
1012 return status;
1015 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
1016 "calling kinit\n", ads_errstr(status)));
1018 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1020 if (ADS_ERR_OK(status)) {
1021 status = ads_sasl_spnego_krb5_bind(ads, &p);
1022 if (!ADS_ERR_OK(status)) {
1023 DEBUG(0,("kinit succeeded but "
1024 "ads_sasl_spnego_krb5_bind failed: %s\n",
1025 ads_errstr(status)));
1029 ads_free_service_principal(&p);
1031 /* only fallback to NTLMSSP if allowed */
1032 if (ADS_ERR_OK(status) ||
1033 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
1034 return status;
1036 } else
1037 #endif
1039 TALLOC_FREE(given_principal);
1042 /* lets do NTLMSSP ... this has the big advantage that we don't need
1043 to sync clocks, and we don't rely on special versions of the krb5
1044 library for HMAC_MD4 encryption */
1045 return ads_sasl_spnego_ntlmssp_bind(ads);
1047 failed:
1048 return status;
1051 #ifdef HAVE_KRB5
1052 #define MAX_GSS_PASSES 3
1054 /* this performs a SASL/gssapi bind
1055 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
1056 is very dependent on correctly configured DNS whereas
1057 this routine is much less fragile
1058 see RFC2078 and RFC2222 for details
1060 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
1062 uint32 minor_status;
1063 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
1064 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
1065 gss_OID mech_type = GSS_C_NULL_OID;
1066 gss_buffer_desc output_token, input_token;
1067 uint32 req_flags, ret_flags;
1068 int conf_state;
1069 struct berval cred;
1070 struct berval *scred = NULL;
1071 int i=0;
1072 int gss_rc, rc;
1073 uint8 *p;
1074 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
1075 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1076 ADS_STATUS status;
1078 input_token.value = NULL;
1079 input_token.length = 0;
1081 status = ads_init_gssapi_cred(ads, &gss_cred);
1082 if (!ADS_ERR_OK(status)) {
1083 goto failed;
1087 * Note: here we always ask the gssapi for sign and seal
1088 * as this is negotiated later after the mutal
1089 * authentication
1091 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
1093 for (i=0; i < MAX_GSS_PASSES; i++) {
1094 gss_rc = gss_init_sec_context(&minor_status,
1095 gss_cred,
1096 &context_handle,
1097 serv_name,
1098 mech_type,
1099 req_flags,
1101 NULL,
1102 &input_token,
1103 NULL,
1104 &output_token,
1105 &ret_flags,
1106 NULL);
1107 if (scred) {
1108 ber_bvfree(scred);
1109 scred = NULL;
1111 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
1112 status = ADS_ERROR_GSS(gss_rc, minor_status);
1113 goto failed;
1116 cred.bv_val = (char *)output_token.value;
1117 cred.bv_len = output_token.length;
1119 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1120 &scred);
1121 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
1122 status = ADS_ERROR(rc);
1123 goto failed;
1126 if (output_token.value) {
1127 gss_release_buffer(&minor_status, &output_token);
1130 if (scred) {
1131 input_token.value = scred->bv_val;
1132 input_token.length = scred->bv_len;
1133 } else {
1134 input_token.value = NULL;
1135 input_token.length = 0;
1138 if (gss_rc == 0) break;
1141 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1142 &conf_state,NULL);
1143 if (scred) {
1144 ber_bvfree(scred);
1145 scred = NULL;
1147 if (gss_rc) {
1148 status = ADS_ERROR_GSS(gss_rc, minor_status);
1149 goto failed;
1152 p = (uint8 *)output_token.value;
1154 #if 0
1155 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1156 #endif
1158 if (p) {
1159 wrap_type = CVAL(p,0);
1160 SCVAL(p,0,0);
1161 max_msg_size = RIVAL(p,0);
1164 gss_release_buffer(&minor_status, &output_token);
1166 if (!(wrap_type & ads->ldap.wrap_type)) {
1168 * the server doesn't supports the wrap
1169 * type we want :-(
1171 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1172 ads->ldap.wrap_type, wrap_type));
1173 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1174 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1175 goto failed;
1178 /* 0x58 is the minimum windows accepts */
1179 if (max_msg_size < 0x58) {
1180 max_msg_size = 0x58;
1183 output_token.length = 4;
1184 output_token.value = SMB_MALLOC(output_token.length);
1185 if (!output_token.value) {
1186 output_token.length = 0;
1187 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1188 goto failed;
1190 p = (uint8 *)output_token.value;
1192 RSIVAL(p,0,max_msg_size);
1193 SCVAL(p,0,ads->ldap.wrap_type);
1196 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1197 * but using ads->config.bind_path is the wrong! It should be
1198 * the DN of the user object!
1200 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1201 * is ok and matches the information flow used in GSS-SPNEGO.
1204 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1205 &output_token, /* used as *input* here. */
1206 &conf_state,
1207 &input_token); /* Used as *output* here. */
1208 if (gss_rc) {
1209 status = ADS_ERROR_GSS(gss_rc, minor_status);
1210 output_token.length = 0;
1211 SAFE_FREE(output_token.value);
1212 goto failed;
1215 /* We've finished with output_token. */
1216 SAFE_FREE(output_token.value);
1217 output_token.length = 0;
1219 cred.bv_val = (char *)input_token.value;
1220 cred.bv_len = input_token.length;
1222 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1223 &scred);
1224 gss_release_buffer(&minor_status, &input_token);
1225 status = ADS_ERROR(rc);
1226 if (!ADS_ERR_OK(status)) {
1227 goto failed;
1230 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1231 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1232 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1233 GSS_C_QOP_DEFAULT,
1234 max_msg_size, &ads->ldap.out.max_unwrapped);
1235 if (gss_rc) {
1236 status = ADS_ERROR_GSS(gss_rc, minor_status);
1237 goto failed;
1240 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1241 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1242 ads->ldap.in.max_wrapped = max_msg_size;
1243 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1244 if (!ADS_ERR_OK(status)) {
1245 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1246 ads_errstr(status)));
1247 goto failed;
1249 /* make sure we don't free context_handle */
1250 context_handle = GSS_C_NO_CONTEXT;
1253 failed:
1254 if (gss_cred != GSS_C_NO_CREDENTIAL)
1255 gss_release_cred(&minor_status, &gss_cred);
1256 if (context_handle != GSS_C_NO_CONTEXT)
1257 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1259 if(scred)
1260 ber_bvfree(scred);
1261 return status;
1264 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1266 ADS_STATUS status;
1267 struct ads_service_principal p;
1269 status = ads_generate_service_principal(ads, NULL, &p);
1270 if (!ADS_ERR_OK(status)) {
1271 return status;
1274 status = ads_sasl_gssapi_do_bind(ads, p.name);
1275 if (ADS_ERR_OK(status)) {
1276 ads_free_service_principal(&p);
1277 return status;
1280 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1281 "calling kinit\n", ads_errstr(status)));
1283 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1285 if (ADS_ERR_OK(status)) {
1286 status = ads_sasl_gssapi_do_bind(ads, p.name);
1289 ads_free_service_principal(&p);
1291 return status;
1294 #endif /* HAVE_KRB5 */
1296 /* mapping between SASL mechanisms and functions */
1297 static struct {
1298 const char *name;
1299 ADS_STATUS (*fn)(ADS_STRUCT *);
1300 } sasl_mechanisms[] = {
1301 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1302 #ifdef HAVE_KRB5
1303 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1304 #endif
1305 {NULL, NULL}
1308 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1310 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1311 char **values;
1312 ADS_STATUS status;
1313 int i, j;
1314 LDAPMessage *res;
1316 /* get a list of supported SASL mechanisms */
1317 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1318 if (!ADS_ERR_OK(status)) return status;
1320 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1322 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1323 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1324 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1325 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1326 } else {
1327 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1330 /* try our supported mechanisms in order */
1331 for (i=0;sasl_mechanisms[i].name;i++) {
1332 /* see if the server supports it */
1333 for (j=0;values && values[j];j++) {
1334 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1335 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1336 retry:
1337 status = sasl_mechanisms[i].fn(ads);
1338 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1339 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1340 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1342 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1343 "retrying with signing enabled\n"));
1344 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1345 goto retry;
1347 ldap_value_free(values);
1348 ldap_msgfree(res);
1349 return status;
1354 ldap_value_free(values);
1355 ldap_msgfree(res);
1356 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1359 #endif /* HAVE_LDAP */