2021-12-08 18:05:17 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-12-08 14:18:56 +03:00
ads sasl code
Copyright ( C ) Andrew Tridgell 2001
2021-12-08 18:05:17 +03:00
2001-12-08 14:18:56 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2001-12-08 14:18:56 +03:00
( at your option ) any later version .
2021-12-08 18:05:17 +03:00
2001-12-08 14:18:56 +03:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2021-12-08 18:05:17 +03:00
2001-12-08 14:18:56 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2001-12-08 14:18:56 +03:00
*/
# include "includes.h"
2015-12-09 17:02:29 +03:00
# include "auth/credentials/credentials.h"
2011-12-27 05:27:11 +04:00
# include "auth/gensec/gensec.h"
# include "auth_generic.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
# include "smb_krb5.h"
2012-04-24 20:37:13 +04:00
# include "system/gssapi.h"
2022-04-25 19:08:33 +03:00
# include "lib/param/param.h"
2023-09-14 20:00:06 +03:00
# include "lib/util/asn1.h"
2001-12-08 14:18:56 +03:00
2022-04-28 18:51:57 +03:00
NTSTATUS ads_simple_creds ( TALLOC_CTX * mem_ctx ,
const char * account_domain ,
const char * account_name ,
const char * password ,
struct cli_credentials * * _creds )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct cli_credentials * creds = NULL ;
struct loadparm_context * lp_ctx = NULL ;
bool ok ;
lp_ctx = loadparm_init_s3 ( frame , loadparm_s3_helpers ( ) ) ;
if ( lp_ctx = = NULL ) {
DBG_ERR ( " loadparm_init_s3 failed \n " ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INVALID_SERVER_STATE ;
}
creds = cli_credentials_init ( mem_ctx ) ;
if ( creds = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
talloc_steal ( frame , creds ) ;
ok = cli_credentials_guess ( creds , lp_ctx ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
if ( account_domain ! = NULL & & account_domain [ 0 ] ! = ' \0 ' ) {
ok = cli_credentials_set_domain ( creds ,
account_domain ,
CRED_SPECIFIED ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
}
if ( password ! = NULL ) {
ok = cli_credentials_set_password ( creds ,
password ,
CRED_SPECIFIED ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
}
cli_credentials_parse_string ( creds ,
account_name ,
CRED_SPECIFIED ) ;
* _creds = talloc_move ( mem_ctx , & creds ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
2002-10-01 22:26:00 +04:00
# ifdef HAVE_LDAP
2001-12-08 14:18:56 +03:00
2017-05-05 15:37:20 +03:00
static ADS_STATUS ads_sasl_gensec_wrap ( struct ads_saslwrap * wrap ,
uint8_t * buf , uint32_t len )
2007-07-18 12:15:42 +04:00
{
2011-12-27 05:27:11 +04:00
struct gensec_security * gensec_security =
2017-05-05 15:37:20 +03:00
talloc_get_type_abort ( wrap - > wrap_private_data ,
2011-12-27 05:27:11 +04:00
struct gensec_security ) ;
2007-07-18 12:15:42 +04:00
NTSTATUS nt_status ;
2011-12-27 05:27:11 +04:00
DATA_BLOB unwrapped , wrapped ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
unwrapped = data_blob_const ( buf , len ) ;
nt_status = gensec_wrap ( gensec_security , frame , & unwrapped , & wrapped ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
TALLOC_FREE ( frame ) ;
return ADS_ERROR_NT ( nt_status ) ;
2007-07-18 12:15:42 +04:00
}
2017-05-05 15:37:20 +03:00
if ( ( wrap - > out . size - 4 ) < wrapped . length ) {
2016-03-05 04:53:45 +03:00
TALLOC_FREE ( frame ) ;
2011-12-27 05:27:11 +04:00
return ADS_ERROR_NT ( NT_STATUS_INTERNAL_ERROR ) ;
}
2007-07-18 12:15:42 +04:00
2011-12-27 05:27:11 +04:00
/* copy the wrapped blob to the right location */
2017-05-05 15:37:20 +03:00
memcpy ( wrap - > out . buf + 4 , wrapped . data , wrapped . length ) ;
2007-07-18 12:15:42 +04:00
/* set how many bytes must be written to the underlying socket */
2017-05-05 15:37:20 +03:00
wrap - > out . left = 4 + wrapped . length ;
2011-12-27 05:27:11 +04:00
TALLOC_FREE ( frame ) ;
2007-07-18 12:15:42 +04:00
return ADS_SUCCESS ;
}
2017-05-05 15:37:20 +03:00
static ADS_STATUS ads_sasl_gensec_unwrap ( struct ads_saslwrap * wrap )
2007-07-18 12:15:42 +04:00
{
2011-12-27 05:27:11 +04:00
struct gensec_security * gensec_security =
2017-05-05 15:37:20 +03:00
talloc_get_type_abort ( wrap - > wrap_private_data ,
2011-12-27 05:27:11 +04:00
struct gensec_security ) ;
2007-07-18 12:15:42 +04:00
NTSTATUS nt_status ;
2011-12-27 05:27:11 +04:00
DATA_BLOB unwrapped , wrapped ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2017-05-05 15:37:20 +03:00
wrapped = data_blob_const ( wrap - > in . buf + 4 , wrap - > in . ofs - 4 ) ;
2011-12-27 05:27:11 +04:00
nt_status = gensec_unwrap ( gensec_security , frame , & wrapped , & unwrapped ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
TALLOC_FREE ( frame ) ;
return ADS_ERROR_NT ( nt_status ) ;
}
if ( wrapped . length < unwrapped . length ) {
TALLOC_FREE ( frame ) ;
return ADS_ERROR_NT ( NT_STATUS_INTERNAL_ERROR ) ;
2007-07-18 12:15:42 +04:00
}
2011-12-27 05:27:11 +04:00
/* copy the wrapped blob to the right location */
2017-05-05 15:37:20 +03:00
memcpy ( wrap - > in . buf + 4 , unwrapped . data , unwrapped . length ) ;
2011-12-27 05:27:11 +04:00
/* set how many bytes must be written to the underlying socket */
2017-05-05 15:37:20 +03:00
wrap - > in . left = unwrapped . length ;
wrap - > in . ofs = 4 ;
2011-12-27 05:27:11 +04:00
TALLOC_FREE ( frame ) ;
2007-07-18 12:15:42 +04:00
return ADS_SUCCESS ;
}
2017-05-05 15:37:20 +03:00
static void ads_sasl_gensec_disconnect ( struct ads_saslwrap * wrap )
2007-07-18 12:15:42 +04:00
{
2011-12-27 05:27:11 +04:00
struct gensec_security * gensec_security =
2017-05-05 15:37:20 +03:00
talloc_get_type_abort ( wrap - > wrap_private_data ,
2011-12-27 05:27:11 +04:00
struct gensec_security ) ;
2007-07-18 12:15:42 +04:00
2011-12-27 05:27:11 +04:00
TALLOC_FREE ( gensec_security ) ;
2007-07-18 12:15:42 +04:00
2017-05-05 15:37:20 +03:00
wrap - > wrap_ops = NULL ;
wrap - > wrap_private_data = NULL ;
2007-07-18 12:15:42 +04:00
}
2015-12-09 15:14:05 +03:00
static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
. name = " gensec " ,
. wrap = ads_sasl_gensec_wrap ,
. unwrap = ads_sasl_gensec_unwrap ,
. disconnect = ads_sasl_gensec_disconnect
2007-07-18 12:15:42 +04:00
} ;
2022-04-25 19:08:33 +03:00
NTSTATUS ads_legacy_creds ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx ,
struct cli_credentials * * _creds )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct cli_credentials * creds = NULL ;
struct loadparm_context * lp_ctx = NULL ;
const char * account_name = NULL ;
fstring acct_name ;
enum credentials_use_kerberos krb5_state ;
uint32_t gensec_features ;
bool ok ;
if ( ads - > auth . flags & ( ADS_AUTH_NO_BIND | ADS_AUTH_ANON_BIND ) ) {
SMB_ASSERT ( ! ( ads - > auth . flags & ADS_AUTH_USER_CREDS ) ) ;
creds = cli_credentials_init_anon ( mem_ctx ) ;
if ( creds = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
talloc_steal ( frame , creds ) ;
goto done ;
}
if ( ads - > auth . user_name = = NULL ) {
/*
* Must use the userPrincipalName value here or sAMAccountName
* and not servicePrincipalName ; found by Guenther Deschner
*/
ads - > auth . user_name = talloc_asprintf ( ads ,
" %s$ " ,
lp_netbios_name ( ) ) ;
if ( ads - > auth . user_name = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
}
if ( ads - > auth . realm = = NULL ) {
if ( ads - > server . realm ! = NULL ) {
ads - > auth . realm = talloc_strdup ( ads , ads - > server . realm ) ;
if ( ads - > auth . realm = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
} else {
ads - > auth . realm = talloc_strdup ( ads , lp_realm ( ) ) ;
if ( ads - > auth . realm = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
}
}
lp_ctx = loadparm_init_s3 ( frame , loadparm_s3_helpers ( ) ) ;
if ( lp_ctx = = NULL ) {
DBG_ERR ( " loadparm_init_s3 failed \n " ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INVALID_SERVER_STATE ;
}
creds = cli_credentials_init ( mem_ctx ) ;
if ( creds = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
talloc_steal ( frame , creds ) ;
ok = cli_credentials_guess ( creds , lp_ctx ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
/*
* This logic was taken from ads_kinit_password ( )
*/
if ( ads - > auth . flags & ADS_AUTH_USER_CREDS ) {
account_name = ads - > auth . user_name ;
} else if ( IS_DC ) {
/* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
account_name = lp_workgroup ( ) ;
} else if ( lp_security ( ) = = SEC_DOMAIN ) {
fstr_sprintf ( acct_name , " %s$ " , lp_netbios_name ( ) ) ;
account_name = acct_name ;
} else {
/* This looks like host/lp_netbios_name()@REA.LM */
account_name = ads - > auth . user_name ;
}
ok = cli_credentials_set_username ( creds ,
account_name ,
CRED_SPECIFIED ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
ok = cli_credentials_set_domain ( creds ,
ads - > auth . realm ,
CRED_SPECIFIED ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
ok = cli_credentials_set_password ( creds ,
ads - > auth . password ,
CRED_SPECIFIED ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
# define __ADS_AUTH_BOTH (ADS_AUTH_ALLOW_NTLMSSP|ADS_AUTH_DISABLE_KERBEROS)
if ( ( ads - > auth . flags & __ADS_AUTH_BOTH ) = = __ADS_AUTH_BOTH ) {
krb5_state = CRED_USE_KERBEROS_DISABLED ;
} else if ( ads - > auth . flags & ADS_AUTH_ALLOW_NTLMSSP ) {
krb5_state = CRED_USE_KERBEROS_DESIRED ;
} else if ( ads - > auth . flags & ADS_AUTH_DISABLE_KERBEROS ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_INCOMPATIBLE_DRIVER_BLOCKED ;
} else {
krb5_state = CRED_USE_KERBEROS_REQUIRED ;
}
cli_credentials_set_kerberos_state ( creds , krb5_state , CRED_SPECIFIED ) ;
gensec_features = cli_credentials_get_gensec_features ( creds ) ;
if ( ads - > auth . flags & ADS_AUTH_SASL_LDAPS ) {
gensec_features & = ~ ( GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL ) ;
} else if ( ads - > auth . flags & ADS_AUTH_SASL_STARTTLS ) {
gensec_features & = ~ ( GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL ) ;
} else if ( ads - > auth . flags & ADS_AUTH_SASL_SEAL ) {
gensec_features | = GENSEC_FEATURE_SIGN ;
gensec_features | = GENSEC_FEATURE_SEAL ;
} else if ( ads - > auth . flags & ADS_AUTH_SASL_SIGN ) {
gensec_features | = GENSEC_FEATURE_SIGN ;
}
cli_credentials_set_gensec_features ( creds , gensec_features , CRED_SPECIFIED ) ;
2024-02-29 16:50:31 +03:00
# ifdef HAVE_KRB5
if ( krb5_state ! = CRED_USE_KERBEROS_DISABLED & &
ads - > auth . password ! = NULL & &
ads - > auth . password [ 0 ] ! = ' \0 ' )
{
ADS_STATUS ads_status ;
const char * error_string = NULL ;
int rc ;
ads - > auth . flags | = ADS_AUTH_GENERATE_KRB5_CONFIG ;
ads_status = ads_connect_cldap_only ( ads ) ;
ads - > auth . flags & = ~ ADS_AUTH_NO_BIND ;
if ( ! ADS_ERR_OK ( ads_status ) ) {
TALLOC_FREE ( frame ) ;
return ads_ntstatus ( ads_status ) ;
}
rc = ads_kinit_password ( ads ) ;
if ( rc = = 0 ) {
rc = cli_credentials_set_ccache ( creds ,
lp_ctx ,
ads - > auth . ccache_name ,
CRED_SPECIFIED ,
& error_string ) ;
if ( rc ! = 0 ) {
ads_status = ADS_ERROR_KRB5 ( rc ) ;
TALLOC_FREE ( frame ) ;
return ads_ntstatus ( ads_status ) ;
}
} else if ( krb5_state = = CRED_USE_KERBEROS_REQUIRED ) {
/*
* Only fail if kerberos is required ,
* otherwise we ignore the kinit failure
* and assume NTLMSSP will make it
*/
ads_status = ADS_ERROR_KRB5 ( rc ) ;
TALLOC_FREE ( frame ) ;
return ads_ntstatus ( ads_status ) ;
}
}
# endif /* HAVE_KRB5 */
2022-04-25 19:08:33 +03:00
done :
* _creds = talloc_move ( mem_ctx , & creds ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
2021-12-08 18:05:17 +03:00
/*
2015-12-09 15:14:05 +03:00
perform a LDAP / SASL / SPNEGO / { NTLMSSP , KRB5 } bind ( just how many layers can
2002-09-25 19:19:00 +04:00
we fit on one socket ? ? )
2001-12-08 14:18:56 +03:00
*/
2015-12-09 15:14:05 +03:00
static ADS_STATUS ads_sasl_spnego_gensec_bind ( ADS_STRUCT * ads ,
2022-04-25 19:08:33 +03:00
struct cli_credentials * creds ,
2015-12-09 15:14:05 +03:00
const char * target_service ,
2024-02-02 14:35:05 +03:00
const char * target_hostname )
2001-12-08 14:18:56 +03:00
{
2007-05-14 16:16:20 +04:00
DATA_BLOB blob_in = data_blob_null ;
DATA_BLOB blob_out = data_blob_null ;
2002-09-25 19:19:00 +04:00
int rc ;
2005-11-04 20:39:42 +03:00
NTSTATUS nt_status ;
2007-07-31 16:30:37 +04:00
ADS_STATUS status ;
2011-12-27 05:27:11 +04:00
struct auth_generic_state * auth_generic_state ;
2024-02-09 12:50:13 +03:00
const char * sasl = " GSS-SPNEGO " ;
2015-12-09 15:14:05 +03:00
const char * sasl_list [ ] = { sasl , NULL } ;
2017-05-05 15:37:20 +03:00
struct ads_saslwrap * wrap = & ads - > ldap_wrap_data ;
2024-02-06 14:35:39 +03:00
const DATA_BLOB * tls_cb = NULL ;
2002-09-25 19:19:00 +04:00
2011-12-27 05:27:11 +04:00
nt_status = auth_generic_client_prepare ( NULL , & auth_generic_state ) ;
2009-12-30 16:13:45 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2005-11-04 20:39:42 +03:00
return ADS_ERROR_NT ( nt_status ) ;
2002-09-25 19:19:00 +04:00
}
2022-04-25 19:08:33 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status = auth_generic_set_creds ( auth_generic_state , creds ) ) ) {
2005-11-04 20:39:42 +03:00
return ADS_ERROR_NT ( nt_status ) ;
2002-09-25 19:19:00 +04:00
}
2015-12-09 15:14:05 +03:00
if ( target_service ! = NULL ) {
nt_status = gensec_set_target_service (
auth_generic_state - > gensec_security ,
target_service ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return ADS_ERROR_NT ( nt_status ) ;
}
}
if ( target_hostname ! = NULL ) {
nt_status = gensec_set_target_hostname (
auth_generic_state - > gensec_security ,
target_hostname ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return ADS_ERROR_NT ( nt_status ) ;
}
}
2024-02-06 14:35:39 +03:00
tls_cb = ads_tls_channel_bindings ( & ads - > ldap_tls_data ) ;
if ( tls_cb ! = NULL ) {
uint32_t initiator_addrtype = 0 ;
const DATA_BLOB * initiator_address = NULL ;
uint32_t acceptor_addrtype = 0 ;
const DATA_BLOB * acceptor_address = NULL ;
const DATA_BLOB * application_data = tls_cb ;
nt_status = gensec_set_channel_bindings ( auth_generic_state - > gensec_security ,
initiator_addrtype ,
initiator_address ,
acceptor_addrtype ,
acceptor_address ,
application_data ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_WARNING ( " Failed to set GENSEC channel bindings: %s \n " ,
nt_errstr ( nt_status ) ) ;
return ADS_ERROR_NT ( nt_status ) ;
}
}
2017-05-05 15:37:20 +03:00
switch ( wrap - > wrap_type ) {
2007-07-18 12:15:42 +04:00
case ADS_SASLWRAP_TYPE_SEAL :
2011-12-27 05:27:11 +04:00
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_SIGN ) ;
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_SEAL ) ;
2007-07-18 12:15:42 +04:00
break ;
case ADS_SASLWRAP_TYPE_SIGN :
if ( ads - > auth . flags & ADS_AUTH_SASL_FORCE ) {
2011-12-27 05:27:11 +04:00
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_SIGN ) ;
2007-07-18 12:15:42 +04:00
} else {
/*
* windows servers are broken with sign only ,
2015-12-09 17:04:02 +03:00
* so we let the NTLMSSP backend to seal here ,
* via GENSEC_FEATURE_LDAP_STYLE .
2007-07-18 12:15:42 +04:00
*/
2011-12-27 05:27:11 +04:00
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_SIGN ) ;
2015-12-09 17:04:02 +03:00
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_LDAP_STYLE ) ;
2007-07-18 12:15:42 +04:00
}
break ;
case ADS_SASLWRAP_TYPE_PLAIN :
break ;
}
2015-12-09 15:14:05 +03:00
nt_status = auth_generic_client_start_by_sasl ( auth_generic_state ,
sasl_list ) ;
2011-12-27 05:27:11 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return ADS_ERROR_NT ( nt_status ) ;
}
2007-07-18 12:15:42 +04:00
2015-12-09 17:02:29 +03:00
rc = LDAP_SASL_BIND_IN_PROGRESS ;
2024-02-02 14:35:05 +03:00
blob_in = data_blob_null ;
2015-12-09 17:02:29 +03:00
blob_out = data_blob_null ;
while ( true ) {
struct berval cred , * scred = NULL ;
2005-11-04 20:39:42 +03:00
2011-12-27 05:27:11 +04:00
nt_status = gensec_update ( auth_generic_state - > gensec_security ,
2013-12-13 22:56:13 +04:00
talloc_tos ( ) , blob_in , & blob_out ) ;
2005-11-04 20:39:42 +03:00
data_blob_free ( & blob_in ) ;
2015-12-09 17:02:29 +03:00
if ( ! NT_STATUS_EQUAL ( nt_status , NT_STATUS_MORE_PROCESSING_REQUIRED )
& & ! NT_STATUS_IS_OK ( nt_status ) )
{
TALLOC_FREE ( auth_generic_state ) ;
2005-11-04 20:39:42 +03:00
data_blob_free ( & blob_out ) ;
2015-12-09 17:02:29 +03:00
return ADS_ERROR_NT ( nt_status ) ;
}
2005-11-04 20:39:42 +03:00
2015-12-09 17:02:29 +03:00
if ( NT_STATUS_IS_OK ( nt_status ) & & rc = = 0 & & blob_out . length = = 0 ) {
break ;
}
2005-11-04 20:39:42 +03:00
2015-12-09 17:02:29 +03:00
cred . bv_val = ( char * ) blob_out . data ;
cred . bv_len = blob_out . length ;
scred = NULL ;
2015-12-09 15:14:05 +03:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , sasl , & cred , NULL , NULL , & scred ) ;
2015-12-09 17:02:29 +03:00
data_blob_free ( & blob_out ) ;
if ( ( rc ! = LDAP_SASL_BIND_IN_PROGRESS ) & & ( rc ! = 0 ) ) {
2005-11-04 20:39:42 +03:00
if ( scred ) {
ber_bvfree ( scred ) ;
}
2011-12-27 05:27:11 +04:00
TALLOC_FREE ( auth_generic_state ) ;
2015-12-09 17:02:29 +03:00
return ADS_ERROR ( rc ) ;
2005-11-04 20:39:42 +03:00
}
2015-12-09 17:02:29 +03:00
if ( scred ) {
blob_in = data_blob_talloc ( talloc_tos ( ) ,
scred - > bv_val ,
scred - > bv_len ) ;
if ( blob_in . length ! = scred - > bv_len ) {
ber_bvfree ( scred ) ;
2011-12-27 05:27:11 +04:00
TALLOC_FREE ( auth_generic_state ) ;
2015-12-09 17:02:29 +03:00
return ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
2005-11-04 20:39:42 +03:00
}
2015-12-09 17:02:29 +03:00
ber_bvfree ( scred ) ;
} else {
blob_in = data_blob_null ;
2005-11-04 20:39:42 +03:00
}
2015-12-09 17:02:29 +03:00
if ( NT_STATUS_IS_OK ( nt_status ) & & rc = = 0 & & blob_in . length = = 0 ) {
break ;
}
}
data_blob_free ( & blob_in ) ;
data_blob_free ( & blob_out ) ;
2017-05-05 15:37:20 +03:00
if ( wrap - > wrap_type > = ADS_SASLWRAP_TYPE_SEAL ) {
2016-03-24 17:50:49 +03:00
bool ok ;
ok = gensec_have_feature ( auth_generic_state - > gensec_security ,
GENSEC_FEATURE_SEAL ) ;
if ( ! ok ) {
DEBUG ( 0 , ( " The gensec feature sealing request, but unavailable \n " ) ) ;
TALLOC_FREE ( auth_generic_state ) ;
return ADS_ERROR_NT ( NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
}
ok = gensec_have_feature ( auth_generic_state - > gensec_security ,
GENSEC_FEATURE_SIGN ) ;
if ( ! ok ) {
DEBUG ( 0 , ( " The gensec feature signing request, but unavailable \n " ) ) ;
TALLOC_FREE ( auth_generic_state ) ;
return ADS_ERROR_NT ( NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
}
2017-05-05 15:37:20 +03:00
} else if ( wrap - > wrap_type > = ADS_SASLWRAP_TYPE_SIGN ) {
2016-03-24 17:50:49 +03:00
bool ok ;
ok = gensec_have_feature ( auth_generic_state - > gensec_security ,
GENSEC_FEATURE_SIGN ) ;
if ( ! ok ) {
DEBUG ( 0 , ( " The gensec feature signing request, but unavailable \n " ) ) ;
TALLOC_FREE ( auth_generic_state ) ;
return ADS_ERROR_NT ( NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
}
}
2024-02-27 15:03:46 +03:00
ads - > auth . expire_time = gensec_expire_time ( auth_generic_state - > gensec_security ) ;
2016-04-18 23:08:38 +03:00
2017-05-05 15:37:20 +03:00
if ( wrap - > wrap_type > ADS_SASLWRAP_TYPE_PLAIN ) {
size_t max_wrapped =
gensec_max_wrapped_size ( auth_generic_state - > gensec_security ) ;
wrap - > out . max_unwrapped =
gensec_max_input_size ( auth_generic_state - > gensec_security ) ;
2015-06-19 02:07:49 +03:00
2017-05-05 15:37:20 +03:00
wrap - > out . sig_size = max_wrapped - wrap - > out . max_unwrapped ;
2016-04-08 11:05:38 +03:00
/*
* Note that we have to truncate this to 0x2C
* ( taken from a capture with LDAP unbind ) , as the
* signature size is not constant for Kerberos with
* arcfour - hmac - md5 .
*/
2017-05-05 15:37:20 +03:00
wrap - > in . min_wrapped = MIN ( wrap - > out . sig_size , 0x2C ) ;
wrap - > in . max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED ;
status = ads_setup_sasl_wrapping ( wrap , ads - > ldap . ld ,
& ads_sasl_gensec_ops ,
auth_generic_state - > gensec_security ) ;
2007-07-31 16:27:25 +04:00
if ( ! ADS_ERR_OK ( status ) ) {
2007-07-31 16:30:37 +04:00
DEBUG ( 0 , ( " ads_setup_sasl_wrapping() failed: %s \n " ,
2007-07-31 16:27:25 +04:00
ads_errstr ( status ) ) ) ;
2011-12-27 05:27:11 +04:00
TALLOC_FREE ( auth_generic_state ) ;
2007-07-31 16:27:25 +04:00
return status ;
}
2011-12-27 05:27:11 +04:00
/* Only keep the gensec_security element around long-term */
talloc_steal ( NULL , auth_generic_state - > gensec_security ) ;
2007-07-18 12:15:42 +04:00
}
2011-12-27 05:27:11 +04:00
TALLOC_FREE ( auth_generic_state ) ;
2004-05-07 03:08:56 +04:00
2005-11-04 20:39:42 +03:00
return ADS_ERROR ( rc ) ;
2001-12-08 14:18:56 +03:00
}
2002-09-25 19:19:00 +04:00
2006-12-12 23:27:01 +03:00
# ifdef HAVE_KRB5
2007-07-31 13:31:47 +04:00
struct ads_service_principal {
2016-03-02 13:33:04 +03:00
char * service ;
char * hostname ;
char * string ;
2007-07-31 13:31:47 +04:00
} ;
static void ads_free_service_principal ( struct ads_service_principal * p )
{
2016-03-02 13:33:04 +03:00
SAFE_FREE ( p - > service ) ;
SAFE_FREE ( p - > hostname ) ;
2007-07-31 13:31:47 +04:00
SAFE_FREE ( p - > string ) ;
ZERO_STRUCTP ( p ) ;
}
2016-03-02 13:33:04 +03:00
static ADS_STATUS ads_guess_target ( ADS_STRUCT * ads ,
char * * service ,
char * * hostname ,
char * * principal )
2011-02-11 13:14:27 +03:00
{
2014-09-23 16:09:41 +04:00
ADS_STATUS status = ADS_ERROR ( LDAP_NO_MEMORY ) ;
2011-02-11 13:14:27 +03:00
char * princ = NULL ;
2014-09-23 16:09:41 +04:00
TALLOC_CTX * frame ;
char * server = NULL ;
char * realm = NULL ;
int rc ;
2011-02-11 13:14:27 +03:00
2014-09-23 16:09:41 +04:00
frame = talloc_stackframe ( ) ;
if ( frame = = NULL ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
2011-02-11 13:14:27 +03:00
2014-09-23 16:09:41 +04:00
if ( ads - > server . realm & & ads - > server . ldap_server ) {
server = strlower_talloc ( frame , ads - > server . ldap_server ) ;
if ( server = = NULL ) {
goto out ;
2012-08-09 04:01:00 +04:00
}
2014-09-23 16:09:41 +04:00
realm = strupper_talloc ( frame , ads - > server . realm ) ;
if ( realm = = NULL ) {
goto out ;
2012-08-09 02:35:28 +04:00
}
2014-09-23 16:09:41 +04:00
/*
* If we got a name which is bigger than a NetBIOS name ,
* but isn ' t a FQDN , create one .
*/
if ( strlen ( server ) > 15 & & strstr ( server , " . " ) = = NULL ) {
char * dnsdomain ;
2011-02-11 13:14:27 +03:00
2014-09-23 16:09:41 +04:00
dnsdomain = strlower_talloc ( frame , ads - > server . realm ) ;
if ( dnsdomain = = NULL ) {
goto out ;
}
2011-02-11 13:14:27 +03:00
2014-09-23 16:09:41 +04:00
server = talloc_asprintf ( frame ,
" %s.%s " ,
server , dnsdomain ) ;
if ( server = = NULL ) {
goto out ;
}
2011-02-11 13:14:27 +03:00
}
} else if ( ads - > config . realm & & ads - > config . ldap_server_name ) {
2014-09-23 16:09:41 +04:00
server = strlower_talloc ( frame , ads - > config . ldap_server_name ) ;
if ( server = = NULL ) {
goto out ;
2011-02-11 13:14:27 +03:00
}
2014-09-23 16:09:41 +04:00
realm = strupper_talloc ( frame , ads - > config . realm ) ;
if ( realm = = NULL ) {
goto out ;
2012-08-09 04:01:00 +04:00
}
2014-09-23 16:09:41 +04:00
/*
* If we got a name which is bigger than a NetBIOS name ,
* but isn ' t a FQDN , create one .
*/
if ( strlen ( server ) > 15 & & strstr ( server , " . " ) = = NULL ) {
char * dnsdomain ;
2011-02-11 13:14:27 +03:00
2014-09-23 16:09:41 +04:00
dnsdomain = strlower_talloc ( frame , ads - > server . realm ) ;
if ( dnsdomain = = NULL ) {
goto out ;
}
2011-02-11 13:14:27 +03:00
2014-09-23 16:09:41 +04:00
server = talloc_asprintf ( frame ,
" %s.%s " ,
server , dnsdomain ) ;
if ( server = = NULL ) {
goto out ;
}
2011-02-11 13:14:27 +03:00
}
}
2014-09-23 16:09:41 +04:00
if ( server = = NULL | | realm = = NULL ) {
goto out ;
}
2016-03-02 13:33:04 +03:00
* service = SMB_STRDUP ( " ldap " ) ;
if ( * service = = NULL ) {
status = ADS_ERROR ( LDAP_PARAM_ERROR ) ;
goto out ;
}
* hostname = SMB_STRDUP ( server ) ;
if ( * hostname = = NULL ) {
SAFE_FREE ( * service ) ;
status = ADS_ERROR ( LDAP_PARAM_ERROR ) ;
goto out ;
}
2014-09-23 16:09:41 +04:00
rc = asprintf ( & princ , " ldap/%s@%s " , server , realm ) ;
if ( rc = = - 1 | | princ = = NULL ) {
2016-03-02 13:33:04 +03:00
SAFE_FREE ( * service ) ;
SAFE_FREE ( * hostname ) ;
2014-09-23 16:09:41 +04:00
status = ADS_ERROR ( LDAP_PARAM_ERROR ) ;
goto out ;
2011-02-11 13:14:27 +03:00
}
2016-03-02 13:33:04 +03:00
* principal = princ ;
2011-02-11 13:14:27 +03:00
2014-09-23 16:09:41 +04:00
status = ADS_SUCCESS ;
out :
TALLOC_FREE ( frame ) ;
return status ;
2011-02-11 13:14:27 +03:00
}
2007-07-31 13:31:47 +04:00
static ADS_STATUS ads_generate_service_principal ( ADS_STRUCT * ads ,
struct ads_service_principal * p )
{
ADS_STATUS status ;
ZERO_STRUCTP ( p ) ;
2016-03-02 13:33:04 +03:00
status = ads_guess_target ( ads ,
& p - > service ,
& p - > hostname ,
& p - > string ) ;
2016-03-02 13:31:01 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
2007-07-31 13:31:47 +04:00
}
2007-09-13 19:59:46 +04:00
return ADS_SUCCESS ;
2007-07-31 13:31:47 +04:00
}
2007-09-12 03:21:50 +04:00
# endif /* HAVE_KRB5 */
2002-09-25 19:19:00 +04:00
2021-12-08 18:05:17 +03:00
/*
2002-09-25 19:19:00 +04:00
this performs a SASL / SPNEGO bind
*/
2022-04-27 14:11:26 +03:00
static ADS_STATUS ads_sasl_spnego_bind ( ADS_STRUCT * ads ,
struct cli_credentials * creds )
2002-09-25 19:19:00 +04:00
{
2016-03-02 13:42:51 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2016-03-15 22:34:27 +03:00
struct ads_service_principal p = { 0 } ;
2002-09-25 19:19:00 +04:00
ADS_STATUS status ;
2022-04-27 13:45:04 +03:00
const char * debug_username = NULL ;
2022-04-27 14:11:26 +03:00
2016-03-02 13:42:51 +03:00
status = ads_generate_service_principal ( ads , & p ) ;
if ( ! ADS_ERR_OK ( status ) ) {
goto done ;
}
2022-04-27 13:45:04 +03:00
debug_username = cli_credentials_get_unparsed_name ( creds , frame ) ;
if ( debug_username = = NULL ) {
status = ADS_ERROR_SYSTEM ( errno ) ;
goto done ;
}
2024-02-29 16:50:31 +03:00
status = ads_sasl_spnego_gensec_bind ( ads ,
creds ,
p . service ,
p . hostname ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DBG_WARNING ( " ads_sasl_spnego_gensec_bind() failed "
" for %s/%s with user[%s]: %s \n " ,
2022-01-07 12:31:19 +03:00
p . service , p . hostname ,
2022-04-27 13:45:04 +03:00
debug_username ,
2022-01-07 12:31:19 +03:00
ads_errstr ( status ) ) ;
2021-12-09 15:43:08 +03:00
goto done ;
}
2016-03-02 13:42:51 +03:00
done :
ads_free_service_principal ( & p ) ;
TALLOC_FREE ( frame ) ;
2002-09-25 19:19:00 +04:00
return status ;
}
2022-04-27 14:11:26 +03:00
ADS_STATUS ads_sasl_bind ( ADS_STRUCT * ads , struct cli_credentials * creds )
2001-12-08 14:18:56 +03:00
{
2002-09-25 19:19:00 +04:00
ADS_STATUS status ;
2017-05-05 15:37:20 +03:00
struct ads_saslwrap * wrap = & ads - > ldap_wrap_data ;
2024-01-30 12:27:58 +03:00
bool tls = false ;
2002-09-25 19:19:00 +04:00
2024-01-30 12:27:58 +03:00
if ( ads - > auth . flags & ADS_AUTH_SASL_LDAPS ) {
tls = true ;
wrap - > wrap_type = ADS_SASLWRAP_TYPE_PLAIN ;
} else if ( ads - > auth . flags & ADS_AUTH_SASL_STARTTLS ) {
tls = true ;
wrap - > wrap_type = ADS_SASLWRAP_TYPE_PLAIN ;
} else if ( ads - > auth . flags & ADS_AUTH_SASL_SEAL ) {
2017-05-05 15:37:20 +03:00
wrap - > wrap_type = ADS_SASLWRAP_TYPE_SEAL ;
2007-07-18 11:45:16 +04:00
} else if ( ads - > auth . flags & ADS_AUTH_SASL_SIGN ) {
2017-05-05 15:37:20 +03:00
wrap - > wrap_type = ADS_SASLWRAP_TYPE_SIGN ;
2007-07-18 11:45:16 +04:00
} else {
2017-05-05 15:37:20 +03:00
wrap - > wrap_type = ADS_SASLWRAP_TYPE_PLAIN ;
2007-07-18 11:45:16 +04:00
}
2024-01-30 12:27:58 +03:00
if ( tls ) {
const DATA_BLOB * tls_cb = NULL ;
tls_cb = ads_tls_channel_bindings ( & ads - > ldap_tls_data ) ;
if ( tls_cb = = NULL ) {
DBG_ERR ( " No TLS channel bindings available \n " ) ;
return ADS_ERROR_NT ( NT_STATUS_INTERNAL_ERROR ) ;
}
}
2010-03-30 11:50:09 +04:00
retry :
2022-04-27 14:11:26 +03:00
status = ads_sasl_spnego_bind ( ads , creds ) ;
2024-01-26 20:08:55 +03:00
if ( status . error_type = = ENUM_ADS_ERROR_LDAP & &
status . err . rc = = LDAP_STRONG_AUTH_REQUIRED & &
2024-01-30 12:27:58 +03:00
! tls & &
2024-01-26 20:08:55 +03:00
wrap - > wrap_type = = ADS_SASLWRAP_TYPE_PLAIN )
{
DEBUG ( 3 , ( " SASL bin got LDAP_STRONG_AUTH_REQUIRED "
" retrying with signing enabled \n " ) ) ;
wrap - > wrap_type = ADS_SASLWRAP_TYPE_SIGN ;
goto retry ;
2002-09-25 19:19:00 +04:00
}
2024-01-26 20:08:55 +03:00
return status ;
2001-12-08 14:18:56 +03:00
}
2006-01-26 00:25:25 +03:00
# endif /* HAVE_LDAP */
2001-12-08 14:18:56 +03:00