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"
2012-07-23 06:47:01 +04:00
# include "lib/param/loadparm.h"
2016-07-06 13:48:11 +03:00
# include "krb5_env.h"
2023-09-14 20:00:06 +03:00
# include "lib/util/asn1.h"
2001-12-08 14:18:56 +03:00
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
} ;
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 ,
enum credentials_use_kerberos krb5_state ,
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 } ;
2016-04-18 23:08:38 +03:00
NTTIME end_nt_time ;
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
}
2011-12-27 05:27:11 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status = auth_generic_set_username ( auth_generic_state , ads - > auth . user_name ) ) ) {
2005-11-04 20:39:42 +03:00
return ADS_ERROR_NT ( nt_status ) ;
}
2011-12-27 05:27:11 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status = auth_generic_set_domain ( auth_generic_state , ads - > auth . realm ) ) ) {
2005-11-04 20:39:42 +03:00
return ADS_ERROR_NT ( nt_status ) ;
}
2011-12-27 05:27:11 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status = auth_generic_set_password ( auth_generic_state , ads - > auth . password ) ) ) {
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 17:02:29 +03:00
cli_credentials_set_kerberos_state ( auth_generic_state - > credentials ,
2020-08-19 16:46:11 +03:00
krb5_state ,
CRED_SPECIFIED ) ;
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 ) ;
}
}
2016-04-18 23:08:38 +03:00
ads - > auth . tgs_expire = LONG_MAX ;
end_nt_time = gensec_expire_time ( auth_generic_state - > gensec_security ) ;
if ( end_nt_time ! = GENSEC_EXPIRE_TIME_INFINITY ) {
struct timeval tv ;
nttime_to_timeval ( & tv , end_nt_time ) ;
ads - > auth . tgs_expire = tv . tv_sec ;
}
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
*/
static ADS_STATUS ads_sasl_spnego_bind ( ADS_STRUCT * ads )
{
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 ;
2017-02-23 13:54:21 +03:00
const char * mech = NULL ;
2002-09-25 19:19:00 +04:00
2016-03-02 13:42:51 +03:00
status = ads_generate_service_principal ( ads , & p ) ;
if ( ! ADS_ERR_OK ( status ) ) {
goto done ;
}
2002-10-01 22:26:00 +04:00
# ifdef HAVE_KRB5
2002-09-25 19:19:00 +04:00
if ( ! ( ads - > auth . flags & ADS_AUTH_DISABLE_KERBEROS ) & &
2024-01-26 20:09:39 +03:00
! is_ipaddress ( p . hostname ) )
2007-02-10 23:29:09 +03:00
{
2017-02-23 13:54:21 +03:00
mech = " KRB5 " ;
2016-07-06 13:44:11 +03:00
if ( ads - > auth . password = = NULL | |
ads - > auth . password [ 0 ] = = ' \0 ' )
{
2024-02-09 12:50:13 +03:00
status = ads_sasl_spnego_gensec_bind ( ads ,
2020-08-20 10:40:41 +03:00
CRED_USE_KERBEROS_REQUIRED ,
2024-02-02 14:35:05 +03:00
p . service , p . hostname ) ;
2016-07-06 13:44:11 +03:00
if ( ADS_ERR_OK ( status ) ) {
ads_free_service_principal ( & p ) ;
goto done ;
}
DEBUG ( 10 , ( " ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
" calling kinit \n " , ads_errstr ( status ) ) ) ;
}
2007-02-08 20:02:39 +03:00
2021-12-08 18:05:17 +03:00
status = ADS_ERROR_KRB5 ( ads_kinit_password ( ads ) ) ;
2004-01-08 11:19:18 +03:00
if ( ADS_ERR_OK ( status ) ) {
2024-02-09 12:50:13 +03:00
status = ads_sasl_spnego_gensec_bind ( ads ,
2020-08-20 10:40:41 +03:00
CRED_USE_KERBEROS_REQUIRED ,
2024-02-02 14:35:05 +03:00
p . service , p . hostname ) ;
2007-09-26 05:02:52 +04:00
if ( ! ADS_ERR_OK ( status ) ) {
2022-01-07 12:31:19 +03:00
DBG_ERR ( " kinit succeeded but "
" SPNEGO bind with Kerberos failed "
" for %s/%s - user[%s], realm[%s]: %s \n " ,
2017-02-23 13:54:21 +03:00
p . service , p . hostname ,
ads - > auth . user_name ,
ads - > auth . realm ,
2022-01-07 12:31:19 +03:00
ads_errstr ( status ) ) ;
2007-09-26 05:02:52 +04:00
}
2003-04-24 18:07:13 +04:00
}
2004-01-08 11:19:18 +03:00
2003-06-10 07:47:42 +04:00
/* only fallback to NTLMSSP if allowed */
2021-12-08 18:05:17 +03:00
if ( ADS_ERR_OK ( status ) | |
2003-06-10 07:47:42 +04:00
! ( ads - > auth . flags & ADS_AUTH_ALLOW_NTLMSSP ) ) {
2016-03-02 13:42:51 +03:00
goto done ;
2003-06-10 07:47:42 +04:00
}
2017-02-23 13:54:21 +03:00
2022-01-07 12:31:19 +03:00
DBG_WARNING ( " SASL bind with Kerberos failed "
" for %s/%s - user[%s], realm[%s]: %s, "
" try to fallback to NTLMSSP \n " ,
p . service , p . hostname ,
ads - > auth . user_name ,
ads - > auth . realm ,
ads_errstr ( status ) ) ;
2007-07-31 13:31:47 +04:00
}
2016-03-02 13:31:01 +03:00
# endif
2004-05-07 03:08:56 +04:00
2002-09-25 19:19:00 +04:00
/* lets do NTLMSSP ... this has the big advantage that we don't need
2021-12-08 18:05:17 +03:00
to sync clocks , and we don ' t rely on special versions of the krb5
2002-09-25 19:19:00 +04:00
library for HMAC_MD4 encryption */
2017-02-23 13:54:21 +03:00
mech = " NTLMSSP " ;
2021-12-09 15:43:08 +03:00
2022-01-03 13:13:06 +03:00
if ( ! ( ads - > auth . flags & ADS_AUTH_ALLOW_NTLMSSP ) ) {
DBG_WARNING ( " We can't use NTLMSSP, it is not allowed. \n " ) ;
status = ADS_ERROR_NT ( NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ) ;
goto done ;
}
2021-12-09 15:43:08 +03:00
if ( lp_weak_crypto ( ) = = SAMBA_WEAK_CRYPTO_DISALLOWED ) {
DBG_WARNING ( " We can't fallback to NTLMSSP, weak crypto is "
" disallowed. \n " ) ;
status = ADS_ERROR_NT ( NT_STATUS_NETWORK_CREDENTIAL_CONFLICT ) ;
goto done ;
}
2024-02-09 12:50:13 +03:00
status = ads_sasl_spnego_gensec_bind ( ads ,
2020-08-20 10:40:41 +03:00
CRED_USE_KERBEROS_DISABLED ,
2024-02-02 14:35:05 +03:00
p . service , p . hostname ) ;
2016-03-02 13:42:51 +03:00
done :
2017-02-23 13:54:21 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 1 , ( " ads_sasl_spnego_gensec_bind(%s) failed "
" for %s/%s with user[%s] realm=[%s]: %s \n " , mech ,
p . service , p . hostname ,
ads - > auth . user_name ,
ads - > auth . realm ,
ads_errstr ( status ) ) ) ;
}
2016-03-02 13:42:51 +03:00
ads_free_service_principal ( & p ) ;
TALLOC_FREE ( frame ) ;
2002-09-25 19:19:00 +04:00
return status ;
}
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_sasl_bind ( ADS_STRUCT * ads )
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 :
2024-01-26 20:08:55 +03:00
status = ads_sasl_spnego_bind ( ads ) ;
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