2 Unix SMB/CIFS implementation.
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/>.
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;
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,
43 nt_status = ntlmssp_sign_packet(ntlmssp_state,
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);
57 /* set how many bytes must be written to the underlying socket */
58 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
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;
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,
83 nt_status = ntlmssp_check_packet(ntlmssp_state,
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;
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 = {
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;
132 struct ntlmssp_state *ntlmssp_state;
134 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
135 return ADS_ERROR_NT(nt_status);
137 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
139 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
140 return ADS_ERROR_NT(nt_status);
142 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
143 return ADS_ERROR_NT(nt_status);
145 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
146 return ADS_ERROR_NT(nt_status);
149 switch (ads->ldap.wrap_type) {
150 case ADS_SASLWRAP_TYPE_SEAL:
151 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
153 case ADS_SASLWRAP_TYPE_SIGN:
154 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
155 features = NTLMSSP_FEATURE_SIGN;
158 * windows servers are broken with sign only,
159 * so we need to use seal here too
161 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
162 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
165 case ADS_SASLWRAP_TYPE_PLAIN:
169 ntlmssp_want_feature(ntlmssp_state, features);
171 blob_in = data_blob_null;
174 nt_status = ntlmssp_update(ntlmssp_state,
176 data_blob_free(&blob_in);
177 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
178 || NT_STATUS_IS_OK(nt_status))
179 && blob_out.length) {
181 /* and wrap it in a SPNEGO wrapper */
182 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
184 /* wrap it in SPNEGO */
185 msg1 = spnego_gen_auth(blob_out);
188 data_blob_free(&blob_out);
190 cred.bv_val = (char *)msg1.data;
191 cred.bv_len = msg1.length;
193 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
194 data_blob_free(&msg1);
195 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
200 ntlmssp_end(&ntlmssp_state);
201 return ADS_ERROR(rc);
204 blob = data_blob(scred->bv_val, scred->bv_len);
207 blob = data_blob_null;
212 ntlmssp_end(&ntlmssp_state);
213 data_blob_free(&blob_out);
214 return ADS_ERROR_NT(nt_status);
218 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
219 DATA_BLOB tmp_blob = data_blob_null;
220 /* the server might give us back two challenges */
221 if (!spnego_parse_challenge(blob, &blob_in,
224 ntlmssp_end(&ntlmssp_state);
225 data_blob_free(&blob);
226 DEBUG(3,("Failed to parse challenges\n"));
227 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
229 data_blob_free(&tmp_blob);
230 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
231 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
234 ntlmssp_end(&ntlmssp_state);
235 data_blob_free(&blob);
236 DEBUG(3,("Failed to parse auth response\n"));
237 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
240 data_blob_free(&blob);
241 data_blob_free(&blob_out);
243 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
245 /* we have a reference conter on ntlmssp_state, if we are signing
246 then the state will be kept by the signing engine */
248 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
249 ads->ldap.out.min = 4;
250 ads->ldap.out.max = 0x0FFFFFFF - NTLMSSP_SIG_SIZE;
251 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
252 ads->ldap.in.min = 4;
253 ads->ldap.in.max = 0x0FFFFFFF;
254 ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
256 ntlmssp_end(&ntlmssp_state);
259 return ADS_ERROR(rc);
263 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
265 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
269 gss_buffer_desc unwrapped, wrapped;
270 int conf_req_flag, conf_state;
272 unwrapped.value = buf;
273 unwrapped.length = len;
275 /* for now request sign and seal */
276 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
278 gss_rc = gss_wrap(&minor_status, context_handle,
279 conf_req_flag, GSS_C_QOP_DEFAULT,
280 &unwrapped, &conf_state,
282 status = ADS_ERROR_GSS(gss_rc, minor_status);
283 if (!ADS_ERR_OK(status)) return status;
285 if (conf_req_flag && conf_state == 0) {
286 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
289 if ((ads->ldap.out.size - 4) < wrapped.length) {
290 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
293 /* copy the wrapped blob to the right location */
294 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
296 /* set how many bytes must be written to the underlying socket */
297 ads->ldap.out.left = 4 + wrapped.length;
299 gss_release_buffer(&minor_status, &wrapped);
304 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
306 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
310 gss_buffer_desc unwrapped, wrapped;
313 wrapped.value = ads->ldap.in.buf + 4;
314 wrapped.length = ads->ldap.in.ofs - 4;
316 gss_rc = gss_unwrap(&minor_status, context_handle,
317 &wrapped, &unwrapped,
318 &conf_state, GSS_C_QOP_DEFAULT);
319 status = ADS_ERROR_GSS(gss_rc, minor_status);
320 if (!ADS_ERR_OK(status)) return status;
322 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
323 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
326 if (wrapped.length < wrapped.length) {
327 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
330 /* copy the wrapped blob to the right location */
331 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
333 /* set how many bytes must be written to the underlying socket */
334 ads->ldap.in.left = unwrapped.length;
335 ads->ldap.in.ofs = 4;
337 gss_release_buffer(&minor_status, &unwrapped);
342 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
344 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
347 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
349 ads->ldap.wrap_ops = NULL;
350 ads->ldap.wrap_private_data = NULL;
353 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
355 .wrap = ads_sasl_gssapi_wrap,
356 .unwrap = ads_sasl_gssapi_unwrap,
357 .disconnect = ads_sasl_gssapi_disconnect
361 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
363 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const char *sname)
369 gss_OID_desc krb5_mech_type =
370 {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
371 gss_OID mech_type = &krb5_mech_type;
372 gss_OID actual_mech_type = GSS_C_NULL_OID;
373 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
374 gss_name_t serv_name;
375 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
376 gss_buffer_desc input_token, output_token;
377 uint32 req_flags, ret_flags;
378 uint32 req_tmp, ret_tmp;
381 struct berval cred, *scred = NULL;
382 krb5_principal principal = NULL;
383 gss_buffer_desc input_name;
384 krb5_context ctx = NULL;
385 krb5_enctype enc_types[] = {
386 #ifdef ENCTYPE_ARCFOUR_HMAC
387 ENCTYPE_ARCFOUR_HMAC,
391 gss_OID_desc nt_principal =
392 {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
394 initialize_krb5_error_table();
395 status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
396 if (!ADS_ERR_OK(status)) {
399 status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
400 if (!ADS_ERR_OK(status)) {
401 krb5_free_context(ctx);
404 status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
405 if (!ADS_ERR_OK(status)) {
406 krb5_free_context(ctx);
411 * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
412 * to point to the *address* of the krb5_principal, and the gss libraries
413 * to a shallow copy of the krb5_principal pointer - so we need to keep
414 * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
415 * Just one more way in which MIT engineers screwed me over.... JRA.
417 input_name.value = &principal;
418 input_name.length = sizeof(principal);
420 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);
422 krb5_free_principal(ctx, principal);
423 krb5_free_context(ctx);
424 return ADS_ERROR_GSS(gss_rc, minor_status);
427 input_token.value = NULL;
428 input_token.length = 0;
430 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
431 switch (ads->ldap.wrap_type) {
432 case ADS_SASLWRAP_TYPE_SEAL:
433 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
435 case ADS_SASLWRAP_TYPE_SIGN:
436 req_flags |= GSS_C_INTEG_FLAG;
438 case ADS_SASLWRAP_TYPE_PLAIN:
442 /* Note: here we explicit ask for the krb5 mech_type */
443 gss_rc = gss_init_sec_context(&minor_status,
456 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
457 status = ADS_ERROR_GSS(gss_rc, minor_status);
462 * As some gssapi krb5 mech implementations
463 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
464 * to req_flags internaly, it's not possible to
465 * use plain or signing only connection via
466 * the gssapi interface.
468 * Because of this we need to check it the ret_flags
469 * has more flags as req_flags and correct the value
470 * of ads->ldap.wrap_type.
472 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
473 * we need to give an error.
475 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
476 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
478 if (req_tmp == ret_tmp) {
479 /* everythings fine... */
481 } else if (req_flags & GSS_C_CONF_FLAG) {
483 * here we wanted sealing but didn't got it
484 * from the gssapi library
486 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
489 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
490 !(ret_flags & GSS_C_INTEG_FLAG)) {
492 * here we wanted siging but didn't got it
493 * from the gssapi library
495 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
498 } else if (ret_flags & GSS_C_CONF_FLAG) {
500 * here we didn't want sealing
501 * but the gssapi library forces it
502 * so correct the needed wrap_type if
503 * the caller didn't forced siging only
505 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
506 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
510 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
511 req_flags = ret_flags;
513 } else if (ret_flags & GSS_C_INTEG_FLAG) {
515 * here we didn't want signing
516 * but the gssapi library forces it
517 * so correct the needed wrap_type if
518 * the caller didn't forced plain
520 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
521 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
525 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
526 req_flags = ret_flags;
529 * This could (should?) not happen
531 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
536 /* and wrap that in a shiny SPNEGO wrapper */
537 unwrapped = data_blob_const(output_token.value, output_token.length);
538 wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
539 gss_release_buffer(&minor_status, &output_token);
540 if (unwrapped.length > wrapped.length) {
541 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
545 cred.bv_val = (char *)wrapped.data;
546 cred.bv_len = wrapped.length;
548 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
550 data_blob_free(&wrapped);
551 if (rc != LDAP_SUCCESS) {
552 status = ADS_ERROR(rc);
557 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
559 wrapped = data_blob_null;
562 ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
565 if (scred) ber_bvfree(scred);
567 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
571 input_token.value = unwrapped.data;
572 input_token.length = unwrapped.length;
575 * As we asked for mutal authentication
576 * we need to pass the servers response
579 gss_rc = gss_init_sec_context(&minor_status,
592 data_blob_free(&unwrapped);
594 status = ADS_ERROR_GSS(gss_rc, minor_status);
598 gss_release_buffer(&minor_status, &output_token);
601 * If we the sign and seal options
602 * doesn't match after getting the response
603 * from the server, we don't want to use the connection
605 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
606 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
608 if (req_tmp != ret_tmp) {
609 /* everythings fine... */
610 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
614 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
615 uint32 max_msg_size = 0x0A000000;
617 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
618 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
620 max_msg_size, &ads->ldap.out.max);
622 status = ADS_ERROR_GSS(gss_rc, minor_status);
626 ads->ldap.out.min = 4;
627 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max;
628 ads->ldap.in.min = 4;
629 ads->ldap.in.max = max_msg_size;
630 ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
631 /* make sure we don't free context_handle */
632 context_handle = GSS_C_NO_CONTEXT;
636 gss_release_name(&minor_status, &serv_name);
637 if (context_handle != GSS_C_NO_CONTEXT)
638 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
639 krb5_free_principal(ctx, principal);
640 krb5_free_context(ctx);
648 perform a LDAP/SASL/SPNEGO/KRB5 bind
650 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
652 DATA_BLOB blob = data_blob_null;
653 struct berval cred, *scred = NULL;
654 DATA_BLOB session_key = data_blob_null;
657 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
658 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
661 rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
662 &ads->auth.tgs_expire);
665 return ADS_ERROR_KRB5(rc);
668 /* now send the auth packet and we should be done */
669 cred.bv_val = (char *)blob.data;
670 cred.bv_len = blob.length;
672 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
674 data_blob_free(&blob);
675 data_blob_free(&session_key);
679 return ADS_ERROR(rc);
682 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *principal)
686 * we only use the gsskrb5 based implementation
687 * when sasl sign or seal is requested.
689 * This has the following reasons:
690 * - it's likely that the gssapi krb5 mech implementation
691 * doesn't support to negotiate plain connections
692 * - the ads_sasl_spnego_rawkrb5_bind is more robust
693 * against clock skew errors
695 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
696 return ads_sasl_spnego_gsskrb5_bind(ads, principal);
699 return ads_sasl_spnego_rawkrb5_bind(ads, principal);
704 this performs a SASL/SPNEGO bind
706 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
708 struct berval *scred=NULL;
712 char *principal = NULL;
713 char *OIDs[ASN1_MAX_OIDS];
715 BOOL got_kerberos_mechanism = False;
718 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
720 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
721 status = ADS_ERROR(rc);
725 blob = data_blob(scred->bv_val, scred->bv_len);
730 file_save("sasl_spnego.dat", blob.data, blob.length);
733 /* the server sent us the first part of the SPNEGO exchange in the negprot
735 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
736 data_blob_free(&blob);
737 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
740 data_blob_free(&blob);
742 /* make sure the server understands kerberos */
743 for (i=0;OIDs[i];i++) {
744 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
746 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
747 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
748 got_kerberos_mechanism = True;
753 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", principal));
756 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
757 got_kerberos_mechanism)
759 /* I've seen a child Windows 2000 domain not send
760 the principal name back in the first round of
761 the SASL bind reply. So we guess based on server
762 name and realm. --jerry */
764 if ( ads->server.realm && ads->server.ldap_server ) {
765 char *server, *server_realm;
767 server = SMB_STRDUP( ads->server.ldap_server );
768 server_realm = SMB_STRDUP( ads->server.realm );
770 if ( !server || !server_realm )
771 return ADS_ERROR(LDAP_NO_MEMORY);
773 strlower_m( server );
774 strupper_m( server_realm );
775 asprintf( &principal, "ldap/%s@%s", server, server_realm );
778 SAFE_FREE( server_realm );
781 return ADS_ERROR(LDAP_NO_MEMORY);
786 status = ads_sasl_spnego_krb5_bind(ads, principal);
787 if (ADS_ERR_OK(status)) {
788 SAFE_FREE(principal);
792 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
793 "calling kinit\n", ads_errstr(status)));
795 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
797 if (ADS_ERR_OK(status)) {
798 status = ads_sasl_spnego_krb5_bind(ads, principal);
801 /* only fallback to NTLMSSP if allowed */
802 if (ADS_ERR_OK(status) ||
803 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
804 SAFE_FREE(principal);
810 SAFE_FREE(principal);
812 /* lets do NTLMSSP ... this has the big advantage that we don't need
813 to sync clocks, and we don't rely on special versions of the krb5
814 library for HMAC_MD4 encryption */
815 return ads_sasl_spnego_ntlmssp_bind(ads);
822 #define MAX_GSS_PASSES 3
824 /* this performs a SASL/gssapi bind
825 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
826 is very dependent on correctly configured DNS whereas
827 this routine is much less fragile
828 see RFC2078 and RFC2222 for details
830 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
833 gss_name_t serv_name;
834 gss_buffer_desc input_name;
835 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
836 gss_OID mech_type = GSS_C_NULL_OID;
837 gss_buffer_desc output_token, input_token;
838 uint32 req_flags, ret_flags;
841 struct berval *scred = NULL;
845 uint32 max_msg_size = 0;
848 krb5_principal principal = NULL;
849 krb5_context ctx = NULL;
850 krb5_enctype enc_types[] = {
851 #ifdef ENCTYPE_ARCFOUR_HMAC
852 ENCTYPE_ARCFOUR_HMAC,
856 gss_OID_desc nt_principal =
857 {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
859 /* we need to fetch a service ticket as the ldap user in the
860 servers realm, regardless of our realm */
861 asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);
863 initialize_krb5_error_table();
864 status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
865 if (!ADS_ERR_OK(status)) {
869 status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
870 if (!ADS_ERR_OK(status)) {
872 krb5_free_context(ctx);
875 status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
876 if (!ADS_ERR_OK(status)) {
878 krb5_free_context(ctx);
882 input_name.value = &principal;
883 input_name.length = sizeof(principal);
885 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);
888 * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
889 * to point to the *address* of the krb5_principal, and the gss libraries
890 * to a shallow copy of the krb5_principal pointer - so we need to keep
891 * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
892 * Just one more way in which MIT engineers screwed me over.... JRA.
898 krb5_free_principal(ctx, principal);
899 krb5_free_context(ctx);
900 return ADS_ERROR_GSS(gss_rc, minor_status);
903 input_token.value = NULL;
904 input_token.length = 0;
906 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
907 switch (ads->ldap.wrap_type) {
908 case ADS_SASLWRAP_TYPE_SEAL:
909 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
911 case ADS_SASLWRAP_TYPE_SIGN:
912 req_flags |= GSS_C_INTEG_FLAG;
914 case ADS_SASLWRAP_TYPE_PLAIN:
918 for (i=0; i < MAX_GSS_PASSES; i++) {
919 gss_rc = gss_init_sec_context(&minor_status,
933 if (input_token.value) {
934 gss_release_buffer(&minor_status, &input_token);
937 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
938 status = ADS_ERROR_GSS(gss_rc, minor_status);
942 cred.bv_val = (char *)output_token.value;
943 cred.bv_len = output_token.length;
945 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
947 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
948 status = ADS_ERROR(rc);
952 if (output_token.value) {
953 gss_release_buffer(&minor_status, &output_token);
957 input_token.value = scred->bv_val;
958 input_token.length = scred->bv_len;
960 input_token.value = NULL;
961 input_token.length = 0;
964 if (gss_rc == 0) break;
967 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
970 status = ADS_ERROR_GSS(gss_rc, minor_status);
974 gss_release_buffer(&minor_status, &input_token);
976 p = (uint8 *)output_token.value;
979 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
983 max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
986 gss_release_buffer(&minor_status, &output_token);
988 output_token.length = 4;
989 output_token.value = SMB_MALLOC(output_token.length);
990 p = (uint8 *)output_token.value;
992 *p++ = ads->ldap.wrap_type;
993 /* choose the same size as the server gave us */
994 *p++ = max_msg_size>>16;
995 *p++ = max_msg_size>>8;
998 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
999 * but using ads->config.bind_path is the wrong! It should be
1000 * the DN of the user object!
1002 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1003 * is ok and matches the information flow used in GSS-SPNEGO.
1006 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1007 &output_token, &conf_state,
1010 status = ADS_ERROR_GSS(gss_rc, minor_status);
1014 free(output_token.value);
1016 cred.bv_val = (char *)input_token.value;
1017 cred.bv_len = input_token.length;
1019 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1021 gss_release_buffer(&minor_status, &input_token);
1022 status = ADS_ERROR(rc);
1023 if (!ADS_ERR_OK(status)) {
1027 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1028 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1029 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1031 max_msg_size, &ads->ldap.out.max);
1033 status = ADS_ERROR_GSS(gss_rc, minor_status);
1037 ads->ldap.out.min = 4;
1038 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max;
1039 ads->ldap.in.min = 4;
1040 ads->ldap.in.max = max_msg_size;
1041 ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1042 /* make sure we don't free context_handle */
1043 context_handle = GSS_C_NO_CONTEXT;
1047 gss_release_name(&minor_status, &serv_name);
1048 if (context_handle != GSS_C_NO_CONTEXT)
1049 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1050 krb5_free_principal(ctx, principal);
1051 krb5_free_context(ctx);
1057 #endif /* HAVE_GGSAPI */
1059 /* mapping between SASL mechanisms and functions */
1062 ADS_STATUS (*fn)(ADS_STRUCT *);
1063 } sasl_mechanisms[] = {
1064 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1066 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1071 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1073 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1079 /* get a list of supported SASL mechanisms */
1080 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1081 if (!ADS_ERR_OK(status)) return status;
1083 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1085 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1086 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1087 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1088 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1090 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1093 /* try our supported mechanisms in order */
1094 for (i=0;sasl_mechanisms[i].name;i++) {
1095 /* see if the server supports it */
1096 for (j=0;values && values[j];j++) {
1097 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1098 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1099 status = sasl_mechanisms[i].fn(ads);
1100 ldap_value_free(values);
1107 ldap_value_free(values);
1109 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1112 #endif /* HAVE_LDAP */