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/>.
21 #include "../libcli/auth/spnego.h"
22 #include "auth/credentials/credentials.h"
23 #include "auth/gensec/gensec.h"
24 #include "auth_generic.h"
27 #include "system/gssapi.h"
28 #include "lib/param/loadparm.h"
33 static ADS_STATUS
ads_sasl_gensec_wrap(struct ads_saslwrap
*wrap
,
34 uint8_t *buf
, uint32_t len
)
36 struct gensec_security
*gensec_security
=
37 talloc_get_type_abort(wrap
->wrap_private_data
,
38 struct gensec_security
);
40 DATA_BLOB unwrapped
, wrapped
;
41 TALLOC_CTX
*frame
= talloc_stackframe();
43 unwrapped
= data_blob_const(buf
, len
);
45 nt_status
= gensec_wrap(gensec_security
, frame
, &unwrapped
, &wrapped
);
46 if (!NT_STATUS_IS_OK(nt_status
)) {
48 return ADS_ERROR_NT(nt_status
);
51 if ((wrap
->out
.size
- 4) < wrapped
.length
) {
53 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
56 /* copy the wrapped blob to the right location */
57 memcpy(wrap
->out
.buf
+ 4, wrapped
.data
, wrapped
.length
);
59 /* set how many bytes must be written to the underlying socket */
60 wrap
->out
.left
= 4 + wrapped
.length
;
67 static ADS_STATUS
ads_sasl_gensec_unwrap(struct ads_saslwrap
*wrap
)
69 struct gensec_security
*gensec_security
=
70 talloc_get_type_abort(wrap
->wrap_private_data
,
71 struct gensec_security
);
73 DATA_BLOB unwrapped
, wrapped
;
74 TALLOC_CTX
*frame
= talloc_stackframe();
76 wrapped
= data_blob_const(wrap
->in
.buf
+ 4, wrap
->in
.ofs
- 4);
78 nt_status
= gensec_unwrap(gensec_security
, frame
, &wrapped
, &unwrapped
);
79 if (!NT_STATUS_IS_OK(nt_status
)) {
81 return ADS_ERROR_NT(nt_status
);
84 if (wrapped
.length
< unwrapped
.length
) {
86 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
89 /* copy the wrapped blob to the right location */
90 memcpy(wrap
->in
.buf
+ 4, unwrapped
.data
, unwrapped
.length
);
92 /* set how many bytes must be written to the underlying socket */
93 wrap
->in
.left
= unwrapped
.length
;
101 static void ads_sasl_gensec_disconnect(struct ads_saslwrap
*wrap
)
103 struct gensec_security
*gensec_security
=
104 talloc_get_type_abort(wrap
->wrap_private_data
,
105 struct gensec_security
);
107 TALLOC_FREE(gensec_security
);
109 wrap
->wrap_ops
= NULL
;
110 wrap
->wrap_private_data
= NULL
;
113 static const struct ads_saslwrap_ops ads_sasl_gensec_ops
= {
115 .wrap
= ads_sasl_gensec_wrap
,
116 .unwrap
= ads_sasl_gensec_unwrap
,
117 .disconnect
= ads_sasl_gensec_disconnect
121 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
122 we fit on one socket??)
124 static ADS_STATUS
ads_sasl_spnego_gensec_bind(ADS_STRUCT
*ads
,
126 enum credentials_use_kerberos krb5_state
,
127 const char *target_service
,
128 const char *target_hostname
,
129 const DATA_BLOB server_blob
)
131 DATA_BLOB blob_in
= data_blob_null
;
132 DATA_BLOB blob_out
= data_blob_null
;
136 struct auth_generic_state
*auth_generic_state
;
137 bool use_spnego_principal
= lp_client_use_spnego_principal();
138 const char *sasl_list
[] = { sasl
, NULL
};
140 struct ads_saslwrap
*wrap
= &ads
->ldap_wrap_data
;
142 nt_status
= auth_generic_client_prepare(NULL
, &auth_generic_state
);
143 if (!NT_STATUS_IS_OK(nt_status
)) {
144 return ADS_ERROR_NT(nt_status
);
147 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_username(auth_generic_state
, ads
->auth
.user_name
))) {
148 return ADS_ERROR_NT(nt_status
);
150 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_domain(auth_generic_state
, ads
->auth
.realm
))) {
151 return ADS_ERROR_NT(nt_status
);
153 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_password(auth_generic_state
, ads
->auth
.password
))) {
154 return ADS_ERROR_NT(nt_status
);
157 if (server_blob
.length
== 0) {
158 use_spnego_principal
= false;
161 if (krb5_state
== CRED_USE_KERBEROS_DISABLED
) {
162 use_spnego_principal
= false;
165 cli_credentials_set_kerberos_state(auth_generic_state
->credentials
,
169 if (target_service
!= NULL
) {
170 nt_status
= gensec_set_target_service(
171 auth_generic_state
->gensec_security
,
173 if (!NT_STATUS_IS_OK(nt_status
)) {
174 return ADS_ERROR_NT(nt_status
);
178 if (target_hostname
!= NULL
) {
179 nt_status
= gensec_set_target_hostname(
180 auth_generic_state
->gensec_security
,
182 if (!NT_STATUS_IS_OK(nt_status
)) {
183 return ADS_ERROR_NT(nt_status
);
187 if (target_service
!= NULL
&& target_hostname
!= NULL
) {
188 use_spnego_principal
= false;
191 switch (wrap
->wrap_type
) {
192 case ADS_SASLWRAP_TYPE_SEAL
:
193 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
194 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SEAL
);
196 case ADS_SASLWRAP_TYPE_SIGN
:
197 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
198 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
201 * windows servers are broken with sign only,
202 * so we let the NTLMSSP backend to seal here,
203 * via GENSEC_FEATURE_LDAP_STYLE.
205 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
206 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_LDAP_STYLE
);
209 case ADS_SASLWRAP_TYPE_PLAIN
:
213 nt_status
= auth_generic_client_start_by_sasl(auth_generic_state
,
215 if (!NT_STATUS_IS_OK(nt_status
)) {
216 return ADS_ERROR_NT(nt_status
);
219 rc
= LDAP_SASL_BIND_IN_PROGRESS
;
220 if (use_spnego_principal
) {
221 blob_in
= data_blob_dup_talloc(talloc_tos(), server_blob
);
222 if (blob_in
.length
== 0) {
223 TALLOC_FREE(auth_generic_state
);
224 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
227 blob_in
= data_blob_null
;
229 blob_out
= data_blob_null
;
232 struct berval cred
, *scred
= NULL
;
234 nt_status
= gensec_update(auth_generic_state
->gensec_security
,
235 talloc_tos(), blob_in
, &blob_out
);
236 data_blob_free(&blob_in
);
237 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)
238 && !NT_STATUS_IS_OK(nt_status
))
240 TALLOC_FREE(auth_generic_state
);
241 data_blob_free(&blob_out
);
242 return ADS_ERROR_NT(nt_status
);
245 if (NT_STATUS_IS_OK(nt_status
) && rc
== 0 && blob_out
.length
== 0) {
249 cred
.bv_val
= (char *)blob_out
.data
;
250 cred
.bv_len
= blob_out
.length
;
252 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, sasl
, &cred
, NULL
, NULL
, &scred
);
253 data_blob_free(&blob_out
);
254 if ((rc
!= LDAP_SASL_BIND_IN_PROGRESS
) && (rc
!= 0)) {
259 TALLOC_FREE(auth_generic_state
);
260 return ADS_ERROR(rc
);
263 blob_in
= data_blob_talloc(talloc_tos(),
266 if (blob_in
.length
!= scred
->bv_len
) {
268 TALLOC_FREE(auth_generic_state
);
269 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
273 blob_in
= data_blob_null
;
275 if (NT_STATUS_IS_OK(nt_status
) && rc
== 0 && blob_in
.length
== 0) {
280 data_blob_free(&blob_in
);
281 data_blob_free(&blob_out
);
283 if (wrap
->wrap_type
>= ADS_SASLWRAP_TYPE_SEAL
) {
286 ok
= gensec_have_feature(auth_generic_state
->gensec_security
,
287 GENSEC_FEATURE_SEAL
);
289 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
290 TALLOC_FREE(auth_generic_state
);
291 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
294 ok
= gensec_have_feature(auth_generic_state
->gensec_security
,
295 GENSEC_FEATURE_SIGN
);
297 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
298 TALLOC_FREE(auth_generic_state
);
299 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
302 } else if (wrap
->wrap_type
>= ADS_SASLWRAP_TYPE_SIGN
) {
305 ok
= gensec_have_feature(auth_generic_state
->gensec_security
,
306 GENSEC_FEATURE_SIGN
);
308 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
309 TALLOC_FREE(auth_generic_state
);
310 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
314 ads
->auth
.tgs_expire
= LONG_MAX
;
315 end_nt_time
= gensec_expire_time(auth_generic_state
->gensec_security
);
316 if (end_nt_time
!= GENSEC_EXPIRE_TIME_INFINITY
) {
318 nttime_to_timeval(&tv
, end_nt_time
);
319 ads
->auth
.tgs_expire
= tv
.tv_sec
;
322 if (wrap
->wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
324 gensec_max_wrapped_size(auth_generic_state
->gensec_security
);
325 wrap
->out
.max_unwrapped
=
326 gensec_max_input_size(auth_generic_state
->gensec_security
);
328 wrap
->out
.sig_size
= max_wrapped
- wrap
->out
.max_unwrapped
;
330 * Note that we have to truncate this to 0x2C
331 * (taken from a capture with LDAP unbind), as the
332 * signature size is not constant for Kerberos with
335 wrap
->in
.min_wrapped
= MIN(wrap
->out
.sig_size
, 0x2C);
336 wrap
->in
.max_wrapped
= ADS_SASL_WRAPPING_IN_MAX_WRAPPED
;
337 status
= ads_setup_sasl_wrapping(wrap
, ads
->ldap
.ld
,
338 &ads_sasl_gensec_ops
,
339 auth_generic_state
->gensec_security
);
340 if (!ADS_ERR_OK(status
)) {
341 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
342 ads_errstr(status
)));
343 TALLOC_FREE(auth_generic_state
);
346 /* Only keep the gensec_security element around long-term */
347 talloc_steal(NULL
, auth_generic_state
->gensec_security
);
349 TALLOC_FREE(auth_generic_state
);
351 return ADS_ERROR(rc
);
355 struct ads_service_principal
{
361 static void ads_free_service_principal(struct ads_service_principal
*p
)
363 SAFE_FREE(p
->service
);
364 SAFE_FREE(p
->hostname
);
365 SAFE_FREE(p
->string
);
369 static ADS_STATUS
ads_guess_target(ADS_STRUCT
*ads
,
374 ADS_STATUS status
= ADS_ERROR(LDAP_NO_MEMORY
);
381 frame
= talloc_stackframe();
383 return ADS_ERROR(LDAP_NO_MEMORY
);
386 if (ads
->server
.realm
&& ads
->server
.ldap_server
) {
387 server
= strlower_talloc(frame
, ads
->server
.ldap_server
);
388 if (server
== NULL
) {
392 realm
= strupper_talloc(frame
, ads
->server
.realm
);
398 * If we got a name which is bigger than a NetBIOS name,
399 * but isn't a FQDN, create one.
401 if (strlen(server
) > 15 && strstr(server
, ".") == NULL
) {
404 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
405 if (dnsdomain
== NULL
) {
409 server
= talloc_asprintf(frame
,
412 if (server
== NULL
) {
416 } else if (ads
->config
.realm
&& ads
->config
.ldap_server_name
) {
417 server
= strlower_talloc(frame
, ads
->config
.ldap_server_name
);
418 if (server
== NULL
) {
422 realm
= strupper_talloc(frame
, ads
->config
.realm
);
428 * If we got a name which is bigger than a NetBIOS name,
429 * but isn't a FQDN, create one.
431 if (strlen(server
) > 15 && strstr(server
, ".") == NULL
) {
434 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
435 if (dnsdomain
== NULL
) {
439 server
= talloc_asprintf(frame
,
442 if (server
== NULL
) {
448 if (server
== NULL
|| realm
== NULL
) {
452 *service
= SMB_STRDUP("ldap");
453 if (*service
== NULL
) {
454 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
457 *hostname
= SMB_STRDUP(server
);
458 if (*hostname
== NULL
) {
460 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
463 rc
= asprintf(&princ
, "ldap/%s@%s", server
, realm
);
464 if (rc
== -1 || princ
== NULL
) {
466 SAFE_FREE(*hostname
);
467 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
473 status
= ADS_SUCCESS
;
479 static ADS_STATUS
ads_generate_service_principal(ADS_STRUCT
*ads
,
480 struct ads_service_principal
*p
)
486 status
= ads_guess_target(ads
,
490 if (!ADS_ERR_OK(status
)) {
497 #endif /* HAVE_KRB5 */
500 this performs a SASL/SPNEGO bind
502 static ADS_STATUS
ads_sasl_spnego_bind(ADS_STRUCT
*ads
)
504 TALLOC_CTX
*frame
= talloc_stackframe();
505 struct ads_service_principal p
= {0};
506 struct berval
*scred
=NULL
;
509 DATA_BLOB blob
= data_blob_null
;
510 char *given_principal
= NULL
;
511 char *OIDs
[ASN1_MAX_OIDS
];
513 bool got_kerberos_mechanism
= False
;
515 const char *mech
= NULL
;
517 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", NULL
, NULL
, NULL
, &scred
);
519 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
520 status
= ADS_ERROR(rc
);
524 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
529 file_save("sasl_spnego.dat", blob
.data
, blob
.length
);
532 /* the server sent us the first part of the SPNEGO exchange in the negprot
534 if (!spnego_parse_negTokenInit(talloc_tos(), blob
, OIDs
, &given_principal
, NULL
) ||
536 status
= ADS_ERROR(LDAP_OPERATIONS_ERROR
);
539 TALLOC_FREE(given_principal
);
541 /* make sure the server understands kerberos */
542 for (i
=0;OIDs
[i
];i
++) {
543 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs
[i
]));
545 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
546 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
547 got_kerberos_mechanism
= True
;
550 talloc_free(OIDs
[i
]);
553 status
= ads_generate_service_principal(ads
, &p
);
554 if (!ADS_ERR_OK(status
)) {
559 if (!(ads
->auth
.flags
& ADS_AUTH_DISABLE_KERBEROS
) &&
560 got_kerberos_mechanism
)
564 if (ads
->auth
.password
== NULL
||
565 ads
->auth
.password
[0] == '\0')
568 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
569 CRED_USE_KERBEROS_REQUIRED
,
570 p
.service
, p
.hostname
,
572 if (ADS_ERR_OK(status
)) {
573 ads_free_service_principal(&p
);
577 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
578 "calling kinit\n", ads_errstr(status
)));
581 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
583 if (ADS_ERR_OK(status
)) {
584 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
585 CRED_USE_KERBEROS_REQUIRED
,
586 p
.service
, p
.hostname
,
588 if (!ADS_ERR_OK(status
)) {
589 DBG_ERR("kinit succeeded but "
590 "SPNEGO bind with Kerberos failed "
591 "for %s/%s - user[%s], realm[%s]: %s\n",
592 p
.service
, p
.hostname
,
599 /* only fallback to NTLMSSP if allowed */
600 if (ADS_ERR_OK(status
) ||
601 !(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
605 DBG_WARNING("SASL bind with Kerberos failed "
606 "for %s/%s - user[%s], realm[%s]: %s, "
607 "try to fallback to NTLMSSP\n",
608 p
.service
, p
.hostname
,
615 /* lets do NTLMSSP ... this has the big advantage that we don't need
616 to sync clocks, and we don't rely on special versions of the krb5
617 library for HMAC_MD4 encryption */
620 if (!(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
621 DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
622 status
= ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT
);
626 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED
) {
627 DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
629 status
= ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT
);
633 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
634 CRED_USE_KERBEROS_DISABLED
,
635 p
.service
, p
.hostname
,
638 if (!ADS_ERR_OK(status
)) {
639 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
640 "for %s/%s with user[%s] realm=[%s]: %s\n", mech
,
641 p
.service
, p
.hostname
,
644 ads_errstr(status
)));
646 ads_free_service_principal(&p
);
648 if (blob
.data
!= NULL
) {
649 data_blob_free(&blob
);
654 /* mapping between SASL mechanisms and functions */
657 ADS_STATUS (*fn
)(ADS_STRUCT
*);
658 } sasl_mechanisms
[] = {
659 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
663 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
665 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
670 struct ads_saslwrap
*wrap
= &ads
->ldap_wrap_data
;
672 /* get a list of supported SASL mechanisms */
673 status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
, "(objectclass=*)", attrs
, &res
);
674 if (!ADS_ERR_OK(status
)) return status
;
676 values
= ldap_get_values(ads
->ldap
.ld
, res
, "supportedSASLMechanisms");
678 if (ads
->auth
.flags
& ADS_AUTH_SASL_SEAL
) {
679 wrap
->wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
680 } else if (ads
->auth
.flags
& ADS_AUTH_SASL_SIGN
) {
681 wrap
->wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
683 wrap
->wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
686 /* try our supported mechanisms in order */
687 for (i
=0;sasl_mechanisms
[i
].name
;i
++) {
688 /* see if the server supports it */
689 for (j
=0;values
&& values
[j
];j
++) {
690 if (strcmp(values
[j
], sasl_mechanisms
[i
].name
) == 0) {
691 DEBUG(4,("Found SASL mechanism %s\n", values
[j
]));
693 status
= sasl_mechanisms
[i
].fn(ads
);
694 if (status
.error_type
== ENUM_ADS_ERROR_LDAP
&&
695 status
.err
.rc
== LDAP_STRONG_AUTH_REQUIRED
&&
696 wrap
->wrap_type
== ADS_SASLWRAP_TYPE_PLAIN
)
698 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
699 "retrying with signing enabled\n"));
700 wrap
->wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
703 ldap_value_free(values
);
710 ldap_value_free(values
);
712 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
715 #endif /* HAVE_LDAP */