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;
133 struct ntlmssp_state *ntlmssp_state;
135 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
136 return ADS_ERROR_NT(nt_status);
138 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
140 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
141 return ADS_ERROR_NT(nt_status);
143 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
144 return ADS_ERROR_NT(nt_status);
146 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
147 return ADS_ERROR_NT(nt_status);
150 switch (ads->ldap.wrap_type) {
151 case ADS_SASLWRAP_TYPE_SEAL:
152 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
154 case ADS_SASLWRAP_TYPE_SIGN:
155 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
156 features = NTLMSSP_FEATURE_SIGN;
159 * windows servers are broken with sign only,
160 * so we need to use seal here too
162 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
163 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
166 case ADS_SASLWRAP_TYPE_PLAIN:
170 ntlmssp_want_feature(ntlmssp_state, features);
172 blob_in = data_blob_null;
175 nt_status = ntlmssp_update(ntlmssp_state,
177 data_blob_free(&blob_in);
178 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
179 || NT_STATUS_IS_OK(nt_status))
180 && blob_out.length) {
182 /* and wrap it in a SPNEGO wrapper */
183 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
185 /* wrap it in SPNEGO */
186 msg1 = spnego_gen_auth(blob_out);
189 data_blob_free(&blob_out);
191 cred.bv_val = (char *)msg1.data;
192 cred.bv_len = msg1.length;
194 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
195 data_blob_free(&msg1);
196 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
201 ntlmssp_end(&ntlmssp_state);
202 return ADS_ERROR(rc);
205 blob = data_blob(scred->bv_val, scred->bv_len);
208 blob = data_blob_null;
213 ntlmssp_end(&ntlmssp_state);
214 data_blob_free(&blob_out);
215 return ADS_ERROR_NT(nt_status);
219 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
220 DATA_BLOB tmp_blob = data_blob_null;
221 /* the server might give us back two challenges */
222 if (!spnego_parse_challenge(blob, &blob_in,
225 ntlmssp_end(&ntlmssp_state);
226 data_blob_free(&blob);
227 DEBUG(3,("Failed to parse challenges\n"));
228 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
230 data_blob_free(&tmp_blob);
231 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
232 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
235 ntlmssp_end(&ntlmssp_state);
236 data_blob_free(&blob);
237 DEBUG(3,("Failed to parse auth response\n"));
238 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
241 data_blob_free(&blob);
242 data_blob_free(&blob_out);
244 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
246 /* we have a reference conter on ntlmssp_state, if we are signing
247 then the state will be kept by the signing engine */
249 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
250 ads->ldap.out.min = 4;
251 ads->ldap.out.max = 0x0FFFFFFF - NTLMSSP_SIG_SIZE;
252 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
253 ads->ldap.in.min = 4;
254 ads->ldap.in.max = 0x0FFFFFFF;
255 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
256 if (!ADS_ERR_OK(status)) {
257 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
258 ads_errstr(status)));
259 ntlmssp_end(&ntlmssp_state);
263 ntlmssp_end(&ntlmssp_state);
266 return ADS_ERROR(rc);
270 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
272 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
276 gss_buffer_desc unwrapped, wrapped;
277 int conf_req_flag, conf_state;
279 unwrapped.value = buf;
280 unwrapped.length = len;
282 /* for now request sign and seal */
283 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
285 gss_rc = gss_wrap(&minor_status, context_handle,
286 conf_req_flag, GSS_C_QOP_DEFAULT,
287 &unwrapped, &conf_state,
289 status = ADS_ERROR_GSS(gss_rc, minor_status);
290 if (!ADS_ERR_OK(status)) return status;
292 if (conf_req_flag && conf_state == 0) {
293 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
296 if ((ads->ldap.out.size - 4) < wrapped.length) {
297 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
300 /* copy the wrapped blob to the right location */
301 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
303 /* set how many bytes must be written to the underlying socket */
304 ads->ldap.out.left = 4 + wrapped.length;
306 gss_release_buffer(&minor_status, &wrapped);
311 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
313 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
317 gss_buffer_desc unwrapped, wrapped;
320 wrapped.value = ads->ldap.in.buf + 4;
321 wrapped.length = ads->ldap.in.ofs - 4;
323 gss_rc = gss_unwrap(&minor_status, context_handle,
324 &wrapped, &unwrapped,
325 &conf_state, GSS_C_QOP_DEFAULT);
326 status = ADS_ERROR_GSS(gss_rc, minor_status);
327 if (!ADS_ERR_OK(status)) return status;
329 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
330 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
333 if (wrapped.length < wrapped.length) {
334 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
337 /* copy the wrapped blob to the right location */
338 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
340 /* set how many bytes must be written to the underlying socket */
341 ads->ldap.in.left = unwrapped.length;
342 ads->ldap.in.ofs = 4;
344 gss_release_buffer(&minor_status, &unwrapped);
349 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
351 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
354 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
356 ads->ldap.wrap_ops = NULL;
357 ads->ldap.wrap_private_data = NULL;
360 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
362 .wrap = ads_sasl_gssapi_wrap,
363 .unwrap = ads_sasl_gssapi_unwrap,
364 .disconnect = ads_sasl_gssapi_disconnect
368 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
370 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
376 gss_OID_desc krb5_mech_type =
377 {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
378 gss_OID mech_type = &krb5_mech_type;
379 gss_OID actual_mech_type = GSS_C_NULL_OID;
380 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
381 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
382 gss_buffer_desc input_token, output_token;
383 uint32 req_flags, ret_flags;
384 uint32 req_tmp, ret_tmp;
387 struct berval cred, *scred = NULL;
389 input_token.value = NULL;
390 input_token.length = 0;
392 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
393 switch (ads->ldap.wrap_type) {
394 case ADS_SASLWRAP_TYPE_SEAL:
395 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
397 case ADS_SASLWRAP_TYPE_SIGN:
398 req_flags |= GSS_C_INTEG_FLAG;
400 case ADS_SASLWRAP_TYPE_PLAIN:
404 /* Note: here we explicit ask for the krb5 mech_type */
405 gss_rc = gss_init_sec_context(&minor_status,
418 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
419 status = ADS_ERROR_GSS(gss_rc, minor_status);
424 * As some gssapi krb5 mech implementations
425 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
426 * to req_flags internaly, it's not possible to
427 * use plain or signing only connection via
428 * the gssapi interface.
430 * Because of this we need to check it the ret_flags
431 * has more flags as req_flags and correct the value
432 * of ads->ldap.wrap_type.
434 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
435 * we need to give an error.
437 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
438 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
440 if (req_tmp == ret_tmp) {
441 /* everythings fine... */
443 } else if (req_flags & GSS_C_CONF_FLAG) {
445 * here we wanted sealing but didn't got it
446 * from the gssapi library
448 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
451 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
452 !(ret_flags & GSS_C_INTEG_FLAG)) {
454 * here we wanted siging but didn't got it
455 * from the gssapi library
457 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
460 } else if (ret_flags & GSS_C_CONF_FLAG) {
462 * here we didn't want sealing
463 * but the gssapi library forces it
464 * so correct the needed wrap_type if
465 * the caller didn't forced siging only
467 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
468 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
472 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
473 req_flags = ret_flags;
475 } else if (ret_flags & GSS_C_INTEG_FLAG) {
477 * here we didn't want signing
478 * but the gssapi library forces it
479 * so correct the needed wrap_type if
480 * the caller didn't forced plain
482 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
483 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
487 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
488 req_flags = ret_flags;
491 * This could (should?) not happen
493 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
498 /* and wrap that in a shiny SPNEGO wrapper */
499 unwrapped = data_blob_const(output_token.value, output_token.length);
500 wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
501 gss_release_buffer(&minor_status, &output_token);
502 if (unwrapped.length > wrapped.length) {
503 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
507 cred.bv_val = (char *)wrapped.data;
508 cred.bv_len = wrapped.length;
510 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
512 data_blob_free(&wrapped);
513 if (rc != LDAP_SUCCESS) {
514 status = ADS_ERROR(rc);
519 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
521 wrapped = data_blob_null;
524 ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
527 if (scred) ber_bvfree(scred);
529 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
533 input_token.value = unwrapped.data;
534 input_token.length = unwrapped.length;
537 * As we asked for mutal authentication
538 * we need to pass the servers response
541 gss_rc = gss_init_sec_context(&minor_status,
554 data_blob_free(&unwrapped);
556 status = ADS_ERROR_GSS(gss_rc, minor_status);
560 gss_release_buffer(&minor_status, &output_token);
563 * If we the sign and seal options
564 * doesn't match after getting the response
565 * from the server, we don't want to use the connection
567 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
568 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
570 if (req_tmp != ret_tmp) {
571 /* everythings fine... */
572 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
576 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
577 uint32 max_msg_size = 0x0A000000;
579 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
580 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
582 max_msg_size, &ads->ldap.out.max);
584 status = ADS_ERROR_GSS(gss_rc, minor_status);
588 ads->ldap.out.min = 4;
589 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max;
590 ads->ldap.in.min = 4;
591 ads->ldap.in.max = max_msg_size;
592 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
593 if (!ADS_ERR_OK(status)) {
594 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
595 ads_errstr(status)));
598 /* make sure we don't free context_handle */
599 context_handle = GSS_C_NO_CONTEXT;
603 if (context_handle != GSS_C_NO_CONTEXT)
604 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
611 struct ads_service_principal {
614 krb5_principal principal;
620 static void ads_free_service_principal(struct ads_service_principal *p)
622 SAFE_FREE(p->string);
627 gss_release_name(&minor_status, &p->name);
631 krb5_free_principal(p->ctx, p->principal);
635 krb5_free_context(p->ctx);
641 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
642 const char *given_principal,
643 struct ads_service_principal *p)
646 krb5_enctype enc_types[] = {
647 #ifdef ENCTYPE_ARCFOUR_HMAC
648 ENCTYPE_ARCFOUR_HMAC,
653 gss_buffer_desc input_name;
654 gss_OID_desc nt_principal =
655 {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
662 /* I've seen a child Windows 2000 domain not send
663 the principal name back in the first round of
664 the SASL bind reply. So we guess based on server
665 name and realm. --jerry */
666 if (given_principal) {
667 p->string = SMB_STRDUP(given_principal);
669 return ADS_ERROR(LDAP_NO_MEMORY);
671 } else if (ads->server.realm && ads->server.ldap_server) {
672 char *server, *server_realm;
674 server = SMB_STRDUP(ads->server.ldap_server);
675 server_realm = SMB_STRDUP(ads->server.realm);
677 if (!server || !server_realm) {
678 return ADS_ERROR(LDAP_NO_MEMORY);
682 strupper_m(server_realm);
683 asprintf(&p->string, "ldap/%s@%s", server, server_realm);
686 SAFE_FREE(server_realm);
689 return ADS_ERROR(LDAP_NO_MEMORY);
691 } else if (ads->config.realm && ads->config.ldap_server_name) {
692 char *server, *server_realm;
694 server = SMB_STRDUP(ads->config.ldap_server_name);
695 server_realm = SMB_STRDUP(ads->config.realm);
697 if (!server || !server_realm) {
698 return ADS_ERROR(LDAP_NO_MEMORY);
702 strupper_m(server_realm);
703 asprintf(&p->string, "ldap/%s@%s", server, server_realm);
706 SAFE_FREE(server_realm);
709 return ADS_ERROR(LDAP_NO_MEMORY);
713 initialize_krb5_error_table();
714 status = ADS_ERROR_KRB5(krb5_init_context(&p->ctx));
715 if (!ADS_ERR_OK(status)) {
716 ads_free_service_principal(p);
719 status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(p->ctx, enc_types));
720 if (!ADS_ERR_OK(status)) {
721 ads_free_service_principal(p);
724 status = ADS_ERROR_KRB5(smb_krb5_parse_name(p->ctx, p->string, &p->principal));
725 if (!ADS_ERR_OK(status)) {
726 ads_free_service_principal(p);
732 * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
733 * to point to the *address* of the krb5_principal, and the gss libraries
734 * to a shallow copy of the krb5_principal pointer - so we need to keep
735 * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
736 * Just one more way in which MIT engineers screwed me over.... JRA.
738 * That's the reason for principal not beeing a local var in this function
740 input_name.value = &p->principal;
741 input_name.length = sizeof(p->principal);
743 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
745 ads_free_service_principal(p);
746 return ADS_ERROR_GSS(gss_rc, minor_status);
754 perform a LDAP/SASL/SPNEGO/KRB5 bind
756 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
758 DATA_BLOB blob = data_blob_null;
759 struct berval cred, *scred = NULL;
760 DATA_BLOB session_key = data_blob_null;
763 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
764 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
767 rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
768 &ads->auth.tgs_expire);
771 return ADS_ERROR_KRB5(rc);
774 /* now send the auth packet and we should be done */
775 cred.bv_val = (char *)blob.data;
776 cred.bv_len = blob.length;
778 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
780 data_blob_free(&blob);
781 data_blob_free(&session_key);
785 return ADS_ERROR(rc);
788 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
789 struct ads_service_principal *p)
793 * we only use the gsskrb5 based implementation
794 * when sasl sign or seal is requested.
796 * This has the following reasons:
797 * - it's likely that the gssapi krb5 mech implementation
798 * doesn't support to negotiate plain connections
799 * - the ads_sasl_spnego_rawkrb5_bind is more robust
800 * against clock skew errors
802 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
803 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
806 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
811 this performs a SASL/SPNEGO bind
813 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
815 struct berval *scred=NULL;
819 char *given_principal = NULL;
820 char *OIDs[ASN1_MAX_OIDS];
822 BOOL got_kerberos_mechanism = False;
825 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
827 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
828 status = ADS_ERROR(rc);
832 blob = data_blob(scred->bv_val, scred->bv_len);
837 file_save("sasl_spnego.dat", blob.data, blob.length);
840 /* the server sent us the first part of the SPNEGO exchange in the negprot
842 if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
843 data_blob_free(&blob);
844 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
847 data_blob_free(&blob);
849 /* make sure the server understands kerberos */
850 for (i=0;OIDs[i];i++) {
851 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
853 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
854 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
855 got_kerberos_mechanism = True;
860 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
863 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
864 got_kerberos_mechanism)
866 struct ads_service_principal p;
868 status = ads_generate_service_principal(ads, given_principal, &p);
869 SAFE_FREE(given_principal);
870 if (!ADS_ERR_OK(status)) {
874 status = ads_sasl_spnego_krb5_bind(ads, &p);
875 if (ADS_ERR_OK(status)) {
876 ads_free_service_principal(&p);
880 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
881 "calling kinit\n", ads_errstr(status)));
883 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
885 if (ADS_ERR_OK(status)) {
886 status = ads_sasl_spnego_krb5_bind(ads, &p);
889 ads_free_service_principal(&p);
891 /* only fallback to NTLMSSP if allowed */
892 if (ADS_ERR_OK(status) ||
893 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
899 SAFE_FREE(given_principal);
902 /* lets do NTLMSSP ... this has the big advantage that we don't need
903 to sync clocks, and we don't rely on special versions of the krb5
904 library for HMAC_MD4 encryption */
905 return ads_sasl_spnego_ntlmssp_bind(ads);
912 #define MAX_GSS_PASSES 3
914 /* this performs a SASL/gssapi bind
915 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
916 is very dependent on correctly configured DNS whereas
917 this routine is much less fragile
918 see RFC2078 and RFC2222 for details
920 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
923 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
924 gss_OID mech_type = GSS_C_NULL_OID;
925 gss_buffer_desc output_token, input_token;
926 uint32 req_flags, ret_flags;
929 struct berval *scred = NULL;
933 uint32 max_msg_size = 0;
936 input_token.value = NULL;
937 input_token.length = 0;
939 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
940 switch (ads->ldap.wrap_type) {
941 case ADS_SASLWRAP_TYPE_SEAL:
942 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
944 case ADS_SASLWRAP_TYPE_SIGN:
945 req_flags |= GSS_C_INTEG_FLAG;
947 case ADS_SASLWRAP_TYPE_PLAIN:
951 for (i=0; i < MAX_GSS_PASSES; i++) {
952 gss_rc = gss_init_sec_context(&minor_status,
969 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
970 status = ADS_ERROR_GSS(gss_rc, minor_status);
974 cred.bv_val = (char *)output_token.value;
975 cred.bv_len = output_token.length;
977 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
979 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
980 status = ADS_ERROR(rc);
984 if (output_token.value) {
985 gss_release_buffer(&minor_status, &output_token);
989 input_token.value = scred->bv_val;
990 input_token.length = scred->bv_len;
992 input_token.value = NULL;
993 input_token.length = 0;
996 if (gss_rc == 0) break;
999 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1006 status = ADS_ERROR_GSS(gss_rc, minor_status);
1010 p = (uint8 *)output_token.value;
1013 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1017 max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
1020 gss_release_buffer(&minor_status, &output_token);
1022 output_token.length = 4;
1023 output_token.value = SMB_MALLOC(output_token.length);
1024 p = (uint8 *)output_token.value;
1026 *p++ = ads->ldap.wrap_type;
1027 /* choose the same size as the server gave us */
1028 *p++ = max_msg_size>>16;
1029 *p++ = max_msg_size>>8;
1030 *p++ = max_msg_size;
1032 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1033 * but using ads->config.bind_path is the wrong! It should be
1034 * the DN of the user object!
1036 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1037 * is ok and matches the information flow used in GSS-SPNEGO.
1040 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1041 &output_token, &conf_state,
1044 status = ADS_ERROR_GSS(gss_rc, minor_status);
1048 free(output_token.value);
1050 cred.bv_val = (char *)input_token.value;
1051 cred.bv_len = input_token.length;
1053 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1055 gss_release_buffer(&minor_status, &input_token);
1056 status = ADS_ERROR(rc);
1057 if (!ADS_ERR_OK(status)) {
1061 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1062 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1063 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1065 max_msg_size, &ads->ldap.out.max);
1067 status = ADS_ERROR_GSS(gss_rc, minor_status);
1071 ads->ldap.out.min = 4;
1072 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max;
1073 ads->ldap.in.min = 4;
1074 ads->ldap.in.max = max_msg_size;
1075 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1076 if (!ADS_ERR_OK(status)) {
1077 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1078 ads_errstr(status)));
1081 /* make sure we don't free context_handle */
1082 context_handle = GSS_C_NO_CONTEXT;
1086 if (context_handle != GSS_C_NO_CONTEXT)
1087 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1094 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1097 struct ads_service_principal p;
1099 status = ads_generate_service_principal(ads, NULL, &p);
1100 if (!ADS_ERR_OK(status)) {
1104 status = ads_sasl_gssapi_do_bind(ads, p.name);
1105 if (ADS_ERR_OK(status)) {
1106 ads_free_service_principal(&p);
1110 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1111 "calling kinit\n", ads_errstr(status)));
1113 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1115 if (ADS_ERR_OK(status)) {
1116 status = ads_sasl_gssapi_do_bind(ads, p.name);
1119 ads_free_service_principal(&p);
1124 #endif /* HAVE_GGSAPI */
1126 /* mapping between SASL mechanisms and functions */
1129 ADS_STATUS (*fn)(ADS_STRUCT *);
1130 } sasl_mechanisms[] = {
1131 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1133 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1138 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1140 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1146 /* get a list of supported SASL mechanisms */
1147 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1148 if (!ADS_ERR_OK(status)) return status;
1150 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1152 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1153 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1154 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1155 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1157 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1160 /* try our supported mechanisms in order */
1161 for (i=0;sasl_mechanisms[i].name;i++) {
1162 /* see if the server supports it */
1163 for (j=0;values && values[j];j++) {
1164 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1165 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1166 status = sasl_mechanisms[i].fn(ads);
1167 ldap_value_free(values);
1174 ldap_value_free(values);
1176 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1179 #endif /* HAVE_LDAP */