param: remove unused define FN_LOCAL_PARM_CHAR()
[Samba/gebeck_regimport.git] / source3 / libads / sasl.c
blob438db05df892dbd6367a17ae6db5aebec18d26c2
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_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
276 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
277 ADS_STATUS status;
278 int gss_rc;
279 uint32 minor_status;
280 gss_buffer_desc unwrapped, wrapped;
281 int conf_req_flag, conf_state;
283 unwrapped.value = buf;
284 unwrapped.length = len;
286 /* for now request sign and seal */
287 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
289 gss_rc = gss_wrap(&minor_status, context_handle,
290 conf_req_flag, GSS_C_QOP_DEFAULT,
291 &unwrapped, &conf_state,
292 &wrapped);
293 status = ADS_ERROR_GSS(gss_rc, minor_status);
294 if (!ADS_ERR_OK(status)) return status;
296 if (conf_req_flag && conf_state == 0) {
297 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
300 if ((ads->ldap.out.size - 4) < wrapped.length) {
301 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
304 /* copy the wrapped blob to the right location */
305 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
307 /* set how many bytes must be written to the underlying socket */
308 ads->ldap.out.left = 4 + wrapped.length;
310 gss_release_buffer(&minor_status, &wrapped);
312 return ADS_SUCCESS;
315 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
317 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
318 ADS_STATUS status;
319 int gss_rc;
320 uint32 minor_status;
321 gss_buffer_desc unwrapped, wrapped;
322 int conf_state;
324 wrapped.value = ads->ldap.in.buf + 4;
325 wrapped.length = ads->ldap.in.ofs - 4;
327 gss_rc = gss_unwrap(&minor_status, context_handle,
328 &wrapped, &unwrapped,
329 &conf_state, GSS_C_QOP_DEFAULT);
330 status = ADS_ERROR_GSS(gss_rc, minor_status);
331 if (!ADS_ERR_OK(status)) return status;
333 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
334 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
337 if (wrapped.length < unwrapped.length) {
338 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
341 /* copy the wrapped blob to the right location */
342 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
344 /* set how many bytes must be written to the underlying socket */
345 ads->ldap.in.left = unwrapped.length;
346 ads->ldap.in.ofs = 4;
348 gss_release_buffer(&minor_status, &unwrapped);
350 return ADS_SUCCESS;
353 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
355 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
356 uint32 minor_status;
358 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
360 ads->ldap.wrap_ops = NULL;
361 ads->ldap.wrap_private_data = NULL;
364 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
365 .name = "gssapi",
366 .wrap = ads_sasl_gssapi_wrap,
367 .unwrap = ads_sasl_gssapi_unwrap,
368 .disconnect = ads_sasl_gssapi_disconnect
372 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
374 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
376 ADS_STATUS status;
377 bool ok;
378 uint32 minor_status;
379 int gss_rc, rc;
380 gss_OID_desc krb5_mech_type =
381 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
382 gss_OID mech_type = &krb5_mech_type;
383 gss_OID actual_mech_type = GSS_C_NULL_OID;
384 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
385 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
386 gss_buffer_desc input_token, output_token;
387 uint32 req_flags, ret_flags;
388 uint32 req_tmp, ret_tmp;
389 DATA_BLOB unwrapped;
390 DATA_BLOB wrapped;
391 struct berval cred, *scred = NULL;
393 input_token.value = NULL;
394 input_token.length = 0;
396 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
397 switch (ads->ldap.wrap_type) {
398 case ADS_SASLWRAP_TYPE_SEAL:
399 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
400 break;
401 case ADS_SASLWRAP_TYPE_SIGN:
402 req_flags |= GSS_C_INTEG_FLAG;
403 break;
404 case ADS_SASLWRAP_TYPE_PLAIN:
405 break;
408 /* Note: here we explicit ask for the krb5 mech_type */
409 gss_rc = gss_init_sec_context(&minor_status,
410 GSS_C_NO_CREDENTIAL,
411 &context_handle,
412 serv_name,
413 mech_type,
414 req_flags,
416 NULL,
417 &input_token,
418 &actual_mech_type,
419 &output_token,
420 &ret_flags,
421 NULL);
422 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
423 status = ADS_ERROR_GSS(gss_rc, minor_status);
424 goto failed;
428 * As some gssapi krb5 mech implementations
429 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
430 * to req_flags internaly, it's not possible to
431 * use plain or signing only connection via
432 * the gssapi interface.
434 * Because of this we need to check it the ret_flags
435 * has more flags as req_flags and correct the value
436 * of ads->ldap.wrap_type.
438 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
439 * we need to give an error.
441 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
442 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
444 if (req_tmp == ret_tmp) {
445 /* everythings fine... */
447 } else if (req_flags & GSS_C_CONF_FLAG) {
449 * here we wanted sealing but didn't got it
450 * from the gssapi library
452 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
453 goto failed;
455 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
456 !(ret_flags & GSS_C_INTEG_FLAG)) {
458 * here we wanted siging but didn't got it
459 * from the gssapi library
461 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
462 goto failed;
464 } else if (ret_flags & GSS_C_CONF_FLAG) {
466 * here we didn't want sealing
467 * but the gssapi library forces it
468 * so correct the needed wrap_type if
469 * the caller didn't forced siging only
471 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
472 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
473 goto failed;
476 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
477 req_flags = ret_flags;
479 } else if (ret_flags & GSS_C_INTEG_FLAG) {
481 * here we didn't want signing
482 * but the gssapi library forces it
483 * so correct the needed wrap_type if
484 * the caller didn't forced plain
486 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
487 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
488 goto failed;
491 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
492 req_flags = ret_flags;
493 } else {
495 * This could (should?) not happen
497 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
498 goto failed;
502 /* and wrap that in a shiny SPNEGO wrapper */
503 unwrapped = data_blob_const(output_token.value, output_token.length);
504 wrapped = spnego_gen_negTokenInit(talloc_tos(),
505 spnego_mechs, &unwrapped, NULL);
506 gss_release_buffer(&minor_status, &output_token);
507 if (unwrapped.length > wrapped.length) {
508 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
509 goto failed;
512 cred.bv_val = (char *)wrapped.data;
513 cred.bv_len = wrapped.length;
515 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
516 &scred);
517 data_blob_free(&wrapped);
518 if (rc != LDAP_SUCCESS) {
519 status = ADS_ERROR(rc);
520 goto failed;
523 if (scred) {
524 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
525 } else {
526 wrapped = data_blob_null;
529 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
530 OID_KERBEROS5_OLD,
531 &unwrapped);
532 if (scred) ber_bvfree(scred);
533 if (!ok) {
534 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
535 goto failed;
538 input_token.value = unwrapped.data;
539 input_token.length = unwrapped.length;
542 * As we asked for mutal authentication
543 * we need to pass the servers response
544 * to gssapi
546 gss_rc = gss_init_sec_context(&minor_status,
547 GSS_C_NO_CREDENTIAL,
548 &context_handle,
549 serv_name,
550 mech_type,
551 req_flags,
553 NULL,
554 &input_token,
555 &actual_mech_type,
556 &output_token,
557 &ret_flags,
558 NULL);
559 data_blob_free(&unwrapped);
560 if (gss_rc) {
561 status = ADS_ERROR_GSS(gss_rc, minor_status);
562 goto failed;
565 gss_release_buffer(&minor_status, &output_token);
568 * If we the sign and seal options
569 * doesn't match after getting the response
570 * from the server, we don't want to use the connection
572 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
573 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
575 if (req_tmp != ret_tmp) {
576 /* everythings fine... */
577 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
578 goto failed;
581 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
582 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
584 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
585 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
586 GSS_C_QOP_DEFAULT,
587 max_msg_size, &ads->ldap.out.max_unwrapped);
588 if (gss_rc) {
589 status = ADS_ERROR_GSS(gss_rc, minor_status);
590 goto failed;
593 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
594 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
595 ads->ldap.in.max_wrapped = max_msg_size;
596 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
597 if (!ADS_ERR_OK(status)) {
598 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
599 ads_errstr(status)));
600 goto failed;
602 /* make sure we don't free context_handle */
603 context_handle = GSS_C_NO_CONTEXT;
606 status = ADS_SUCCESS;
608 failed:
609 if (context_handle != GSS_C_NO_CONTEXT)
610 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
611 return status;
614 #endif /* HAVE_KRB5 */
616 #ifdef HAVE_KRB5
617 struct ads_service_principal {
618 char *string;
619 #ifdef HAVE_KRB5
620 gss_name_t name;
621 #endif
624 static void ads_free_service_principal(struct ads_service_principal *p)
626 SAFE_FREE(p->string);
628 #ifdef HAVE_KRB5
629 if (p->name) {
630 uint32 minor_status;
631 gss_release_name(&minor_status, &p->name);
633 #endif
634 ZERO_STRUCTP(p);
638 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
639 char **returned_principal)
641 char *princ = NULL;
643 if (ads->server.realm && ads->server.ldap_server) {
644 char *server, *server_realm;
646 server = SMB_STRDUP(ads->server.ldap_server);
647 server_realm = SMB_STRDUP(ads->server.realm);
649 if (!server || !server_realm) {
650 SAFE_FREE(server);
651 SAFE_FREE(server_realm);
652 return ADS_ERROR(LDAP_NO_MEMORY);
655 if (!strlower_m(server)) {
656 SAFE_FREE(server);
657 SAFE_FREE(server_realm);
658 return ADS_ERROR(LDAP_NO_MEMORY);
661 if (!strupper_m(server_realm)) {
662 SAFE_FREE(server);
663 SAFE_FREE(server_realm);
664 return ADS_ERROR(LDAP_NO_MEMORY);
667 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
668 SAFE_FREE(server);
669 SAFE_FREE(server_realm);
670 return ADS_ERROR(LDAP_NO_MEMORY);
673 SAFE_FREE(server);
674 SAFE_FREE(server_realm);
676 if (!princ) {
677 return ADS_ERROR(LDAP_NO_MEMORY);
679 } else if (ads->config.realm && ads->config.ldap_server_name) {
680 char *server, *server_realm;
682 server = SMB_STRDUP(ads->config.ldap_server_name);
683 server_realm = SMB_STRDUP(ads->config.realm);
685 if (!server || !server_realm) {
686 SAFE_FREE(server);
687 SAFE_FREE(server_realm);
688 return ADS_ERROR(LDAP_NO_MEMORY);
691 if (!strlower_m(server)) {
692 SAFE_FREE(server);
693 SAFE_FREE(server_realm);
694 return ADS_ERROR(LDAP_NO_MEMORY);
697 if (!strupper_m(server_realm)) {
698 SAFE_FREE(server);
699 SAFE_FREE(server_realm);
700 return ADS_ERROR(LDAP_NO_MEMORY);
702 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
703 SAFE_FREE(server);
704 SAFE_FREE(server_realm);
705 return ADS_ERROR(LDAP_NO_MEMORY);
708 SAFE_FREE(server);
709 SAFE_FREE(server_realm);
711 if (!princ) {
712 return ADS_ERROR(LDAP_NO_MEMORY);
716 if (!princ) {
717 return ADS_ERROR(LDAP_PARAM_ERROR);
720 *returned_principal = princ;
722 return ADS_SUCCESS;
725 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
726 const char *given_principal,
727 struct ads_service_principal *p)
729 ADS_STATUS status;
730 #ifdef HAVE_KRB5
731 gss_buffer_desc input_name;
732 /* GSS_KRB5_NT_PRINCIPAL_NAME */
733 gss_OID_desc nt_principal =
734 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
735 uint32 minor_status;
736 int gss_rc;
737 #endif
739 ZERO_STRUCTP(p);
741 /* I've seen a child Windows 2000 domain not send
742 the principal name back in the first round of
743 the SASL bind reply. So we guess based on server
744 name and realm. --jerry */
745 /* Also try best guess when we get the w2k8 ignore principal
746 back, or when we are configured to ignore it - gd,
747 abartlet */
749 if (!lp_client_use_spnego_principal() ||
750 !given_principal ||
751 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
753 status = ads_guess_service_principal(ads, &p->string);
754 if (!ADS_ERR_OK(status)) {
755 return status;
757 } else {
758 p->string = SMB_STRDUP(given_principal);
759 if (!p->string) {
760 return ADS_ERROR(LDAP_NO_MEMORY);
764 #ifdef HAVE_KRB5
765 input_name.value = p->string;
766 input_name.length = strlen(p->string);
768 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
769 if (gss_rc) {
770 ads_free_service_principal(p);
771 return ADS_ERROR_GSS(gss_rc, minor_status);
773 #endif
775 return ADS_SUCCESS;
779 perform a LDAP/SASL/SPNEGO/KRB5 bind
781 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
783 DATA_BLOB blob = data_blob_null;
784 struct berval cred, *scred = NULL;
785 DATA_BLOB session_key = data_blob_null;
786 int rc;
788 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
789 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
792 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
793 ads->auth.time_offset, &blob, &session_key, 0,
794 &ads->auth.tgs_expire);
796 if (rc) {
797 return ADS_ERROR_KRB5(rc);
800 /* now send the auth packet and we should be done */
801 cred.bv_val = (char *)blob.data;
802 cred.bv_len = blob.length;
804 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
806 data_blob_free(&blob);
807 data_blob_free(&session_key);
808 if(scred)
809 ber_bvfree(scred);
811 return ADS_ERROR(rc);
814 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
815 struct ads_service_principal *p)
817 #ifdef HAVE_KRB5
819 * we only use the gsskrb5 based implementation
820 * when sasl sign or seal is requested.
822 * This has the following reasons:
823 * - it's likely that the gssapi krb5 mech implementation
824 * doesn't support to negotiate plain connections
825 * - the ads_sasl_spnego_rawkrb5_bind is more robust
826 * against clock skew errors
828 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
829 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
831 #endif
832 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
834 #endif /* HAVE_KRB5 */
837 this performs a SASL/SPNEGO bind
839 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
841 struct berval *scred=NULL;
842 int rc, i;
843 ADS_STATUS status;
844 DATA_BLOB blob;
845 char *given_principal = NULL;
846 char *OIDs[ASN1_MAX_OIDS];
847 #ifdef HAVE_KRB5
848 bool got_kerberos_mechanism = False;
849 #endif
851 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
853 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
854 status = ADS_ERROR(rc);
855 goto failed;
858 blob = data_blob(scred->bv_val, scred->bv_len);
860 ber_bvfree(scred);
862 #if 0
863 file_save("sasl_spnego.dat", blob.data, blob.length);
864 #endif
866 /* the server sent us the first part of the SPNEGO exchange in the negprot
867 reply */
868 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
869 OIDs[0] == NULL) {
870 data_blob_free(&blob);
871 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
872 goto failed;
874 data_blob_free(&blob);
876 /* make sure the server understands kerberos */
877 for (i=0;OIDs[i];i++) {
878 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
879 #ifdef HAVE_KRB5
880 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
881 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
882 got_kerberos_mechanism = True;
884 #endif
885 talloc_free(OIDs[i]);
887 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
889 #ifdef HAVE_KRB5
890 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
891 got_kerberos_mechanism)
893 struct ads_service_principal p;
895 status = ads_generate_service_principal(ads, given_principal, &p);
896 TALLOC_FREE(given_principal);
897 if (!ADS_ERR_OK(status)) {
898 return status;
901 status = ads_sasl_spnego_krb5_bind(ads, &p);
902 if (ADS_ERR_OK(status)) {
903 ads_free_service_principal(&p);
904 return status;
907 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
908 "calling kinit\n", ads_errstr(status)));
910 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
912 if (ADS_ERR_OK(status)) {
913 status = ads_sasl_spnego_krb5_bind(ads, &p);
914 if (!ADS_ERR_OK(status)) {
915 DEBUG(0,("kinit succeeded but "
916 "ads_sasl_spnego_krb5_bind failed: %s\n",
917 ads_errstr(status)));
921 ads_free_service_principal(&p);
923 /* only fallback to NTLMSSP if allowed */
924 if (ADS_ERR_OK(status) ||
925 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
926 return status;
928 } else
929 #endif
931 TALLOC_FREE(given_principal);
934 /* lets do NTLMSSP ... this has the big advantage that we don't need
935 to sync clocks, and we don't rely on special versions of the krb5
936 library for HMAC_MD4 encryption */
937 return ads_sasl_spnego_ntlmssp_bind(ads);
939 failed:
940 return status;
943 #ifdef HAVE_KRB5
944 #define MAX_GSS_PASSES 3
946 /* this performs a SASL/gssapi bind
947 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
948 is very dependent on correctly configured DNS whereas
949 this routine is much less fragile
950 see RFC2078 and RFC2222 for details
952 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
954 uint32 minor_status;
955 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
956 gss_OID mech_type = GSS_C_NULL_OID;
957 gss_buffer_desc output_token, input_token;
958 uint32 req_flags, ret_flags;
959 int conf_state;
960 struct berval cred;
961 struct berval *scred = NULL;
962 int i=0;
963 int gss_rc, rc;
964 uint8 *p;
965 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
966 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
967 ADS_STATUS status;
969 input_token.value = NULL;
970 input_token.length = 0;
973 * Note: here we always ask the gssapi for sign and seal
974 * as this is negotiated later after the mutal
975 * authentication
977 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
979 for (i=0; i < MAX_GSS_PASSES; i++) {
980 gss_rc = gss_init_sec_context(&minor_status,
981 GSS_C_NO_CREDENTIAL,
982 &context_handle,
983 serv_name,
984 mech_type,
985 req_flags,
987 NULL,
988 &input_token,
989 NULL,
990 &output_token,
991 &ret_flags,
992 NULL);
993 if (scred) {
994 ber_bvfree(scred);
995 scred = NULL;
997 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
998 status = ADS_ERROR_GSS(gss_rc, minor_status);
999 goto failed;
1002 cred.bv_val = (char *)output_token.value;
1003 cred.bv_len = output_token.length;
1005 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1006 &scred);
1007 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
1008 status = ADS_ERROR(rc);
1009 goto failed;
1012 if (output_token.value) {
1013 gss_release_buffer(&minor_status, &output_token);
1016 if (scred) {
1017 input_token.value = scred->bv_val;
1018 input_token.length = scred->bv_len;
1019 } else {
1020 input_token.value = NULL;
1021 input_token.length = 0;
1024 if (gss_rc == 0) break;
1027 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1028 &conf_state,NULL);
1029 if (scred) {
1030 ber_bvfree(scred);
1031 scred = NULL;
1033 if (gss_rc) {
1034 status = ADS_ERROR_GSS(gss_rc, minor_status);
1035 goto failed;
1038 p = (uint8 *)output_token.value;
1040 #if 0
1041 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1042 #endif
1044 if (p) {
1045 wrap_type = CVAL(p,0);
1046 SCVAL(p,0,0);
1047 max_msg_size = RIVAL(p,0);
1050 gss_release_buffer(&minor_status, &output_token);
1052 if (!(wrap_type & ads->ldap.wrap_type)) {
1054 * the server doesn't supports the wrap
1055 * type we want :-(
1057 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1058 ads->ldap.wrap_type, wrap_type));
1059 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1060 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1061 goto failed;
1064 /* 0x58 is the minimum windows accepts */
1065 if (max_msg_size < 0x58) {
1066 max_msg_size = 0x58;
1069 output_token.length = 4;
1070 output_token.value = SMB_MALLOC(output_token.length);
1071 if (!output_token.value) {
1072 output_token.length = 0;
1073 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1074 goto failed;
1076 p = (uint8 *)output_token.value;
1078 RSIVAL(p,0,max_msg_size);
1079 SCVAL(p,0,ads->ldap.wrap_type);
1082 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1083 * but using ads->config.bind_path is the wrong! It should be
1084 * the DN of the user object!
1086 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1087 * is ok and matches the information flow used in GSS-SPNEGO.
1090 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1091 &output_token, /* used as *input* here. */
1092 &conf_state,
1093 &input_token); /* Used as *output* here. */
1094 if (gss_rc) {
1095 status = ADS_ERROR_GSS(gss_rc, minor_status);
1096 output_token.length = 0;
1097 SAFE_FREE(output_token.value);
1098 goto failed;
1101 /* We've finished with output_token. */
1102 SAFE_FREE(output_token.value);
1103 output_token.length = 0;
1105 cred.bv_val = (char *)input_token.value;
1106 cred.bv_len = input_token.length;
1108 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1109 &scred);
1110 gss_release_buffer(&minor_status, &input_token);
1111 status = ADS_ERROR(rc);
1112 if (!ADS_ERR_OK(status)) {
1113 goto failed;
1116 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1117 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1118 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1119 GSS_C_QOP_DEFAULT,
1120 max_msg_size, &ads->ldap.out.max_unwrapped);
1121 if (gss_rc) {
1122 status = ADS_ERROR_GSS(gss_rc, minor_status);
1123 goto failed;
1126 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1127 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1128 ads->ldap.in.max_wrapped = max_msg_size;
1129 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1130 if (!ADS_ERR_OK(status)) {
1131 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1132 ads_errstr(status)));
1133 goto failed;
1135 /* make sure we don't free context_handle */
1136 context_handle = GSS_C_NO_CONTEXT;
1139 failed:
1141 if (context_handle != GSS_C_NO_CONTEXT)
1142 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1144 if(scred)
1145 ber_bvfree(scred);
1146 return status;
1149 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1151 ADS_STATUS status;
1152 struct ads_service_principal p;
1154 status = ads_generate_service_principal(ads, NULL, &p);
1155 if (!ADS_ERR_OK(status)) {
1156 return status;
1159 status = ads_sasl_gssapi_do_bind(ads, p.name);
1160 if (ADS_ERR_OK(status)) {
1161 ads_free_service_principal(&p);
1162 return status;
1165 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1166 "calling kinit\n", ads_errstr(status)));
1168 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1170 if (ADS_ERR_OK(status)) {
1171 status = ads_sasl_gssapi_do_bind(ads, p.name);
1174 ads_free_service_principal(&p);
1176 return status;
1179 #endif /* HAVE_KRB5 */
1181 /* mapping between SASL mechanisms and functions */
1182 static struct {
1183 const char *name;
1184 ADS_STATUS (*fn)(ADS_STRUCT *);
1185 } sasl_mechanisms[] = {
1186 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1187 #ifdef HAVE_KRB5
1188 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1189 #endif
1190 {NULL, NULL}
1193 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1195 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1196 char **values;
1197 ADS_STATUS status;
1198 int i, j;
1199 LDAPMessage *res;
1201 /* get a list of supported SASL mechanisms */
1202 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1203 if (!ADS_ERR_OK(status)) return status;
1205 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1207 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1208 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1209 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1210 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1211 } else {
1212 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1215 /* try our supported mechanisms in order */
1216 for (i=0;sasl_mechanisms[i].name;i++) {
1217 /* see if the server supports it */
1218 for (j=0;values && values[j];j++) {
1219 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1220 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1221 retry:
1222 status = sasl_mechanisms[i].fn(ads);
1223 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1224 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1225 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1227 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1228 "retrying with signing enabled\n"));
1229 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1230 goto retry;
1232 ldap_value_free(values);
1233 ldap_msgfree(res);
1234 return status;
1239 ldap_value_free(values);
1240 ldap_msgfree(res);
1241 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1244 #endif /* HAVE_LDAP */