2001-12-08 11:18:56 +00:00
/*
2002-01-30 06:08:46 +00:00
Unix SMB / CIFS implementation .
2001-12-08 11:18:56 +00:00
ads sasl code
Copyright ( C ) Andrew Tridgell 2001
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 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2001-12-08 11:18:56 +00:00
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2001-12-08 11:18:56 +00:00
*/
# include "includes.h"
2009-09-17 00:21:01 +02:00
# include "../libcli/auth/spnego.h"
2015-12-09 15:02:29 +01:00
# include "auth/credentials/credentials.h"
2011-12-27 12:27:11 +11:00
# include "auth/gensec/gensec.h"
# include "auth_generic.h"
2010-07-02 00:32:52 +02:00
# include "ads.h"
# include "smb_krb5.h"
2012-04-24 19:37:13 +03:00
# include "system/gssapi.h"
2012-07-23 12:47:01 +10:00
# include "lib/param/loadparm.h"
2016-07-06 12:48:11 +02:00
# include "krb5_env.h"
2001-12-08 11:18:56 +00:00
2002-10-01 18:26:00 +00:00
# ifdef HAVE_LDAP
2001-12-08 11:18:56 +00:00
2015-12-09 13:14:05 +01:00
static ADS_STATUS ads_sasl_gensec_wrap ( ADS_STRUCT * ads , uint8_t * buf , uint32_t len )
2007-07-18 08:15:42 +00:00
{
2011-12-27 12:27:11 +11:00
struct gensec_security * gensec_security =
talloc_get_type_abort ( ads - > ldap . wrap_private_data ,
struct gensec_security ) ;
2007-07-18 08:15:42 +00:00
NTSTATUS nt_status ;
2011-12-27 12:27:11 +11: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 08:15:42 +00:00
}
2011-12-27 12:27:11 +11:00
if ( ( ads - > ldap . out . size - 4 ) < wrapped . length ) {
2016-03-05 02:53:45 +01:00
TALLOC_FREE ( frame ) ;
2011-12-27 12:27:11 +11:00
return ADS_ERROR_NT ( NT_STATUS_INTERNAL_ERROR ) ;
}
2007-07-18 08:15:42 +00:00
2011-12-27 12:27:11 +11:00
/* copy the wrapped blob to the right location */
memcpy ( ads - > ldap . out . buf + 4 , wrapped . data , wrapped . length ) ;
2007-07-18 08:15:42 +00:00
/* set how many bytes must be written to the underlying socket */
2011-12-27 12:27:11 +11:00
ads - > ldap . out . left = 4 + wrapped . length ;
TALLOC_FREE ( frame ) ;
2007-07-18 08:15:42 +00:00
return ADS_SUCCESS ;
}
2015-12-09 13:14:05 +01:00
static ADS_STATUS ads_sasl_gensec_unwrap ( ADS_STRUCT * ads )
2007-07-18 08:15:42 +00:00
{
2011-12-27 12:27:11 +11:00
struct gensec_security * gensec_security =
talloc_get_type_abort ( ads - > ldap . wrap_private_data ,
struct gensec_security ) ;
2007-07-18 08:15:42 +00:00
NTSTATUS nt_status ;
2011-12-27 12:27:11 +11:00
DATA_BLOB unwrapped , wrapped ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
wrapped = data_blob_const ( ads - > ldap . in . buf + 4 , ads - > ldap . in . ofs - 4 ) ;
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 08:15:42 +00:00
}
2011-12-27 12:27:11 +11:00
/* copy the wrapped blob to the right location */
memcpy ( ads - > ldap . in . buf + 4 , unwrapped . data , unwrapped . length ) ;
/* set how many bytes must be written to the underlying socket */
ads - > ldap . in . left = unwrapped . length ;
ads - > ldap . in . ofs = 4 ;
TALLOC_FREE ( frame ) ;
2007-07-18 08:15:42 +00:00
return ADS_SUCCESS ;
}
2015-12-09 13:14:05 +01:00
static void ads_sasl_gensec_disconnect ( ADS_STRUCT * ads )
2007-07-18 08:15:42 +00:00
{
2011-12-27 12:27:11 +11:00
struct gensec_security * gensec_security =
talloc_get_type_abort ( ads - > ldap . wrap_private_data ,
struct gensec_security ) ;
2007-07-18 08:15:42 +00:00
2011-12-27 12:27:11 +11:00
TALLOC_FREE ( gensec_security ) ;
2007-07-18 08:15:42 +00:00
ads - > ldap . wrap_ops = NULL ;
ads - > ldap . wrap_private_data = NULL ;
}
2015-12-09 13:14:05 +01: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 08:15:42 +00:00
} ;
2002-09-25 15:19:00 +00:00
/*
2015-12-09 13:14:05 +01:00
perform a LDAP / SASL / SPNEGO / { NTLMSSP , KRB5 } bind ( just how many layers can
2002-09-25 15:19:00 +00:00
we fit on one socket ? ? )
2001-12-08 11:18:56 +00:00
*/
2015-12-09 13:14:05 +01:00
static ADS_STATUS ads_sasl_spnego_gensec_bind ( ADS_STRUCT * ads ,
const char * sasl ,
enum credentials_use_kerberos krb5_state ,
const char * target_service ,
const char * target_hostname ,
const DATA_BLOB server_blob )
2001-12-08 11:18:56 +00:00
{
2007-05-14 12:16:20 +00:00
DATA_BLOB blob_in = data_blob_null ;
DATA_BLOB blob_out = data_blob_null ;
2002-09-25 15:19:00 +00:00
int rc ;
2005-11-04 17:39:42 +00:00
NTSTATUS nt_status ;
2007-07-31 12:30:37 +00:00
ADS_STATUS status ;
2011-12-27 12:27:11 +11:00
struct auth_generic_state * auth_generic_state ;
2015-12-09 13:14:05 +01:00
bool use_spnego_principal = lp_client_use_spnego_principal ( ) ;
const char * sasl_list [ ] = { sasl , NULL } ;
2016-04-18 23:08:38 +03:00
NTTIME end_nt_time ;
2002-09-25 15:19:00 +00:00
2011-12-27 12:27:11 +11:00
nt_status = auth_generic_client_prepare ( NULL , & auth_generic_state ) ;
2009-12-30 14:13:45 +01:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2005-11-04 17:39:42 +00:00
return ADS_ERROR_NT ( nt_status ) ;
2002-09-25 15:19:00 +00:00
}
2011-12-27 12:27:11 +11:00
if ( ! NT_STATUS_IS_OK ( nt_status = auth_generic_set_username ( auth_generic_state , ads - > auth . user_name ) ) ) {
2005-11-04 17:39:42 +00:00
return ADS_ERROR_NT ( nt_status ) ;
}
2011-12-27 12:27:11 +11:00
if ( ! NT_STATUS_IS_OK ( nt_status = auth_generic_set_domain ( auth_generic_state , ads - > auth . realm ) ) ) {
2005-11-04 17:39:42 +00:00
return ADS_ERROR_NT ( nt_status ) ;
}
2011-12-27 12:27:11 +11:00
if ( ! NT_STATUS_IS_OK ( nt_status = auth_generic_set_password ( auth_generic_state , ads - > auth . password ) ) ) {
2005-11-04 17:39:42 +00:00
return ADS_ERROR_NT ( nt_status ) ;
2002-09-25 15:19:00 +00:00
}
2015-12-09 13:14:05 +01:00
if ( server_blob . length = = 0 ) {
use_spnego_principal = false ;
}
if ( krb5_state = = CRED_DONT_USE_KERBEROS ) {
use_spnego_principal = false ;
}
2015-12-09 15:02:29 +01:00
cli_credentials_set_kerberos_state ( auth_generic_state - > credentials ,
2015-12-09 13:14:05 +01:00
krb5_state ) ;
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 ) ;
}
}
if ( target_service ! = NULL & & target_hostname ! = NULL ) {
use_spnego_principal = false ;
}
2015-12-09 15:02:29 +01:00
2007-07-18 08:15:42 +00:00
switch ( ads - > ldap . wrap_type ) {
case ADS_SASLWRAP_TYPE_SEAL :
2011-12-27 12:27:11 +11: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 08:15:42 +00:00
break ;
case ADS_SASLWRAP_TYPE_SIGN :
if ( ads - > auth . flags & ADS_AUTH_SASL_FORCE ) {
2011-12-27 12:27:11 +11:00
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_SIGN ) ;
2007-07-18 08:15:42 +00:00
} else {
/*
* windows servers are broken with sign only ,
2015-12-09 15:04:02 +01:00
* so we let the NTLMSSP backend to seal here ,
* via GENSEC_FEATURE_LDAP_STYLE .
2007-07-18 08:15:42 +00:00
*/
2011-12-27 12:27:11 +11:00
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_SIGN ) ;
2015-12-09 15:04:02 +01:00
gensec_want_feature ( auth_generic_state - > gensec_security , GENSEC_FEATURE_LDAP_STYLE ) ;
2007-07-18 08:15:42 +00:00
}
break ;
case ADS_SASLWRAP_TYPE_PLAIN :
break ;
}
2015-12-09 13:14:05 +01:00
nt_status = auth_generic_client_start_by_sasl ( auth_generic_state ,
sasl_list ) ;
2011-12-27 12:27:11 +11:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return ADS_ERROR_NT ( nt_status ) ;
}
2007-07-18 08:15:42 +00:00
2015-12-09 15:02:29 +01:00
rc = LDAP_SASL_BIND_IN_PROGRESS ;
nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED ;
2015-12-09 13:14:05 +01:00
if ( use_spnego_principal ) {
blob_in = data_blob_dup_talloc ( talloc_tos ( ) , server_blob ) ;
if ( blob_in . length = = 0 ) {
TALLOC_FREE ( auth_generic_state ) ;
return ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
} else {
blob_in = data_blob_null ;
}
2015-12-09 15:02:29 +01:00
blob_out = data_blob_null ;
while ( true ) {
struct berval cred , * scred = NULL ;
2005-11-04 17:39:42 +00:00
2011-12-27 12:27:11 +11:00
nt_status = gensec_update ( auth_generic_state - > gensec_security ,
2013-12-13 19:56:13 +01:00
talloc_tos ( ) , blob_in , & blob_out ) ;
2005-11-04 17:39:42 +00:00
data_blob_free ( & blob_in ) ;
2015-12-09 15:02:29 +01: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 17:39:42 +00:00
data_blob_free ( & blob_out ) ;
2015-12-09 15:02:29 +01:00
return ADS_ERROR_NT ( nt_status ) ;
}
2005-11-04 17:39:42 +00:00
2015-12-09 15:02:29 +01:00
if ( NT_STATUS_IS_OK ( nt_status ) & & rc = = 0 & & blob_out . length = = 0 ) {
break ;
}
2005-11-04 17:39:42 +00:00
2015-12-09 15:02:29 +01:00
cred . bv_val = ( char * ) blob_out . data ;
cred . bv_len = blob_out . length ;
scred = NULL ;
2015-12-09 13:14:05 +01:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , sasl , & cred , NULL , NULL , & scred ) ;
2015-12-09 15:02:29 +01:00
data_blob_free ( & blob_out ) ;
if ( ( rc ! = LDAP_SASL_BIND_IN_PROGRESS ) & & ( rc ! = 0 ) ) {
2005-11-04 17:39:42 +00:00
if ( scred ) {
ber_bvfree ( scred ) ;
}
2011-12-27 12:27:11 +11:00
TALLOC_FREE ( auth_generic_state ) ;
2015-12-09 15:02:29 +01:00
return ADS_ERROR ( rc ) ;
2005-11-04 17:39:42 +00:00
}
2015-12-09 15:02:29 +01: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 12:27:11 +11:00
TALLOC_FREE ( auth_generic_state ) ;
2015-12-09 15:02:29 +01:00
return ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
2005-11-04 17:39:42 +00:00
}
2015-12-09 15:02:29 +01:00
ber_bvfree ( scred ) ;
} else {
blob_in = data_blob_null ;
2005-11-04 17:39:42 +00:00
}
2015-12-09 15:02:29 +01: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 ) ;
2016-03-24 15:50:49 +01:00
if ( ads - > ldap . wrap_type > = ADS_SASLWRAP_TYPE_SEAL ) {
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 ) ;
}
} else if ( ads - > ldap . wrap_type > = ADS_SASLWRAP_TYPE_SIGN ) {
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 ;
}
2007-07-18 08:15:42 +00:00
if ( ads - > ldap . wrap_type > ADS_SASLWRAP_TYPE_PLAIN ) {
2015-06-19 01:07:49 +02:00
size_t max_wrapped = gensec_max_wrapped_size ( auth_generic_state - > gensec_security ) ;
ads - > ldap . out . max_unwrapped = gensec_max_input_size ( auth_generic_state - > gensec_security ) ;
ads - > ldap . out . sig_size = max_wrapped - ads - > ldap . out . max_unwrapped ;
2016-04-08 10:05:38 +02: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 .
*/
ads - > ldap . in . min_wrapped = MIN ( ads - > ldap . out . sig_size , 0x2C ) ;
2016-04-22 16:31:55 +02:00
ads - > ldap . in . max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED ;
2015-12-09 13:14:05 +01:00
status = ads_setup_sasl_wrapping ( ads , & ads_sasl_gensec_ops , auth_generic_state - > gensec_security ) ;
2007-07-31 12:27:25 +00:00
if ( ! ADS_ERR_OK ( status ) ) {
2007-07-31 12:30:37 +00:00
DEBUG ( 0 , ( " ads_setup_sasl_wrapping() failed: %s \n " ,
2007-07-31 12:27:25 +00:00
ads_errstr ( status ) ) ) ;
2011-12-27 12:27:11 +11:00
TALLOC_FREE ( auth_generic_state ) ;
2007-07-31 12:27:25 +00:00
return status ;
}
2011-12-27 12:27:11 +11:00
/* Only keep the gensec_security element around long-term */
talloc_steal ( NULL , auth_generic_state - > gensec_security ) ;
2007-07-18 08:15:42 +00:00
}
2011-12-27 12:27:11 +11:00
TALLOC_FREE ( auth_generic_state ) ;
2004-05-06 23:08:56 +00:00
2005-11-04 17:39:42 +00:00
return ADS_ERROR ( rc ) ;
2001-12-08 11:18:56 +00:00
}
2002-09-25 15:19:00 +00:00
2012-02-13 11:23:15 +11:00
# ifdef HAVE_KRB5
2012-09-07 14:14:08 -04:00
static ADS_STATUS ads_init_gssapi_cred ( ADS_STRUCT * ads , gss_cred_id_t * cred )
{
ADS_STATUS status ;
krb5_context kctx ;
krb5_error_code kerr ;
krb5_ccache kccache = NULL ;
uint32_t maj , min ;
* cred = GSS_C_NO_CREDENTIAL ;
if ( ! ads - > auth . ccache_name ) {
return ADS_SUCCESS ;
}
kerr = krb5_init_context ( & kctx ) ;
if ( kerr ) {
return ADS_ERROR_KRB5 ( kerr ) ;
}
# ifdef HAVE_GSS_KRB5_IMPORT_CRED
kerr = krb5_cc_resolve ( kctx , ads - > auth . ccache_name , & kccache ) ;
if ( kerr ) {
status = ADS_ERROR_KRB5 ( kerr ) ;
goto done ;
}
maj = gss_krb5_import_cred ( & min , kccache , NULL , NULL , cred ) ;
if ( maj ! = GSS_S_COMPLETE ) {
status = ADS_ERROR_GSS ( maj , min ) ;
goto done ;
}
# else
/* We need to fallback to overriding the default creds.
* This operation is not thread safe as it changes the process
* environment variable , but we do not have any better option
* with older kerberos libraries */
{
const char * oldccname = NULL ;
oldccname = getenv ( " KRB5CCNAME " ) ;
setenv ( " KRB5CCNAME " , ads - > auth . ccache_name , 1 ) ;
maj = gss_acquire_cred ( & min , GSS_C_NO_NAME , GSS_C_INDEFINITE ,
NULL , GSS_C_INITIATE , cred , NULL , NULL ) ;
if ( oldccname ) {
setenv ( " KRB5CCNAME " , oldccname , 1 ) ;
} else {
unsetenv ( " KRB5CCNAME " ) ;
}
if ( maj ! = GSS_S_COMPLETE ) {
status = ADS_ERROR_GSS ( maj , min ) ;
goto done ;
}
}
# endif
status = ADS_SUCCESS ;
done :
if ( ! ADS_ERR_OK ( status ) & & kccache ! = NULL ) {
krb5_cc_close ( kctx , kccache ) ;
}
krb5_free_context ( kctx ) ;
return status ;
}
2015-04-18 08:40:14 -07:00
static ADS_STATUS ads_sasl_gssapi_wrap ( ADS_STRUCT * ads , uint8_t * buf , uint32_t len )
2007-07-18 08:19:13 +00:00
{
2007-09-29 06:44:39 +00:00
gss_ctx_id_t context_handle = ( gss_ctx_id_t ) ads - > ldap . wrap_private_data ;
2007-07-18 08:19:13 +00:00
ADS_STATUS status ;
int gss_rc ;
2015-04-18 08:40:14 -07:00
uint32_t minor_status ;
2007-07-18 08:19:13 +00:00
gss_buffer_desc unwrapped , wrapped ;
int conf_req_flag , conf_state ;
unwrapped . value = buf ;
unwrapped . length = len ;
/* for now request sign and seal */
conf_req_flag = ( ads - > ldap . wrap_type = = ADS_SASLWRAP_TYPE_SEAL ) ;
gss_rc = gss_wrap ( & minor_status , context_handle ,
conf_req_flag , GSS_C_QOP_DEFAULT ,
& unwrapped , & conf_state ,
& wrapped ) ;
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
if ( conf_req_flag & & conf_state = = 0 ) {
return ADS_ERROR_NT ( NT_STATUS_ACCESS_DENIED ) ;
}
if ( ( ads - > ldap . out . size - 4 ) < wrapped . length ) {
return ADS_ERROR_NT ( NT_STATUS_INTERNAL_ERROR ) ;
}
/* copy the wrapped blob to the right location */
memcpy ( ads - > ldap . out . buf + 4 , wrapped . value , wrapped . length ) ;
/* set how many bytes must be written to the underlying socket */
ads - > ldap . out . left = 4 + wrapped . length ;
gss_release_buffer ( & minor_status , & wrapped ) ;
return ADS_SUCCESS ;
}
static ADS_STATUS ads_sasl_gssapi_unwrap ( ADS_STRUCT * ads )
{
2007-09-29 06:44:39 +00:00
gss_ctx_id_t context_handle = ( gss_ctx_id_t ) ads - > ldap . wrap_private_data ;
2007-07-18 08:19:13 +00:00
ADS_STATUS status ;
int gss_rc ;
2015-04-18 08:40:14 -07:00
uint32_t minor_status ;
2007-07-18 08:19:13 +00:00
gss_buffer_desc unwrapped , wrapped ;
int conf_state ;
wrapped . value = ads - > ldap . in . buf + 4 ;
wrapped . length = ads - > ldap . in . ofs - 4 ;
gss_rc = gss_unwrap ( & minor_status , context_handle ,
& wrapped , & unwrapped ,
& conf_state , GSS_C_QOP_DEFAULT ) ;
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
if ( ads - > ldap . wrap_type = = ADS_SASLWRAP_TYPE_SEAL & & conf_state = = 0 ) {
return ADS_ERROR_NT ( NT_STATUS_ACCESS_DENIED ) ;
}
2007-12-06 09:53:42 +01:00
if ( wrapped . length < unwrapped . length ) {
2007-07-18 08:19:13 +00:00
return ADS_ERROR_NT ( NT_STATUS_INTERNAL_ERROR ) ;
}
/* copy the wrapped blob to the right location */
memcpy ( ads - > ldap . in . buf + 4 , unwrapped . value , unwrapped . length ) ;
/* set how many bytes must be written to the underlying socket */
ads - > ldap . in . left = unwrapped . length ;
ads - > ldap . in . ofs = 4 ;
gss_release_buffer ( & minor_status , & unwrapped ) ;
return ADS_SUCCESS ;
}
static void ads_sasl_gssapi_disconnect ( ADS_STRUCT * ads )
{
2007-09-29 06:44:39 +00:00
gss_ctx_id_t context_handle = ( gss_ctx_id_t ) ads - > ldap . wrap_private_data ;
2015-04-18 08:40:14 -07:00
uint32_t minor_status ;
2007-07-18 08:19:13 +00:00
gss_delete_sec_context ( & minor_status , & context_handle , GSS_C_NO_BUFFER ) ;
ads - > ldap . wrap_ops = NULL ;
ads - > ldap . wrap_private_data = NULL ;
}
static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
. name = " gssapi " ,
. wrap = ads_sasl_gssapi_wrap ,
. unwrap = ads_sasl_gssapi_unwrap ,
. disconnect = ads_sasl_gssapi_disconnect
} ;
2007-07-25 10:34:16 +00:00
2012-02-13 11:23:15 +11:00
# endif /* HAVE_KRB5 */
2007-07-18 08:19:13 +00:00
2006-12-12 20:27:01 +00:00
# ifdef HAVE_KRB5
2007-07-31 09:31:47 +00:00
struct ads_service_principal {
2016-03-02 11:33:04 +01:00
char * service ;
char * hostname ;
char * string ;
2012-02-13 11:23:15 +11:00
# ifdef HAVE_KRB5
2016-03-02 11:33:04 +01:00
gss_name_t name ;
2007-07-31 09:31:47 +00:00
# endif
} ;
static void ads_free_service_principal ( struct ads_service_principal * p )
{
2016-03-02 11:33:04 +01:00
SAFE_FREE ( p - > service ) ;
SAFE_FREE ( p - > hostname ) ;
2007-07-31 09:31:47 +00:00
SAFE_FREE ( p - > string ) ;
2012-02-13 11:23:15 +11:00
# ifdef HAVE_KRB5
2007-07-31 09:31:47 +00:00
if ( p - > name ) {
2015-04-18 08:40:14 -07:00
uint32_t minor_status ;
2007-07-31 09:31:47 +00:00
gss_release_name ( & minor_status , & p - > name ) ;
}
# endif
ZERO_STRUCTP ( p ) ;
}
2016-03-02 11:33:04 +01:00
static ADS_STATUS ads_guess_target ( ADS_STRUCT * ads ,
char * * service ,
char * * hostname ,
char * * principal )
2011-02-11 11:14:27 +01:00
{
2014-09-23 14:09:41 +02:00
ADS_STATUS status = ADS_ERROR ( LDAP_NO_MEMORY ) ;
2011-02-11 11:14:27 +01:00
char * princ = NULL ;
2014-09-23 14:09:41 +02:00
TALLOC_CTX * frame ;
char * server = NULL ;
char * realm = NULL ;
int rc ;
2011-02-11 11:14:27 +01:00
2014-09-23 14:09:41 +02:00
frame = talloc_stackframe ( ) ;
if ( frame = = NULL ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
2011-02-11 11:14:27 +01:00
2014-09-23 14:09:41 +02:00
if ( ads - > server . realm & & ads - > server . ldap_server ) {
server = strlower_talloc ( frame , ads - > server . ldap_server ) ;
if ( server = = NULL ) {
goto out ;
2012-08-08 17:01:00 -07:00
}
2014-09-23 14:09:41 +02:00
realm = strupper_talloc ( frame , ads - > server . realm ) ;
if ( realm = = NULL ) {
goto out ;
2012-08-08 15:35:28 -07:00
}
2014-09-23 14:09:41 +02: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 11:14:27 +01:00
2014-09-23 14:09:41 +02:00
dnsdomain = strlower_talloc ( frame , ads - > server . realm ) ;
if ( dnsdomain = = NULL ) {
goto out ;
}
2011-02-11 11:14:27 +01:00
2014-09-23 14:09:41 +02:00
server = talloc_asprintf ( frame ,
" %s.%s " ,
server , dnsdomain ) ;
if ( server = = NULL ) {
goto out ;
}
2011-02-11 11:14:27 +01:00
}
} else if ( ads - > config . realm & & ads - > config . ldap_server_name ) {
2014-09-23 14:09:41 +02:00
server = strlower_talloc ( frame , ads - > config . ldap_server_name ) ;
if ( server = = NULL ) {
goto out ;
2011-02-11 11:14:27 +01:00
}
2014-09-23 14:09:41 +02:00
realm = strupper_talloc ( frame , ads - > config . realm ) ;
if ( realm = = NULL ) {
goto out ;
2012-08-08 17:01:00 -07:00
}
2014-09-23 14:09:41 +02: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 11:14:27 +01:00
2014-09-23 14:09:41 +02:00
dnsdomain = strlower_talloc ( frame , ads - > server . realm ) ;
if ( dnsdomain = = NULL ) {
goto out ;
}
2011-02-11 11:14:27 +01:00
2014-09-23 14:09:41 +02:00
server = talloc_asprintf ( frame ,
" %s.%s " ,
server , dnsdomain ) ;
if ( server = = NULL ) {
goto out ;
}
2011-02-11 11:14:27 +01:00
}
}
2014-09-23 14:09:41 +02:00
if ( server = = NULL | | realm = = NULL ) {
goto out ;
}
2016-03-02 11:33:04 +01: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 14:09:41 +02:00
rc = asprintf ( & princ , " ldap/%s@%s " , server , realm ) ;
if ( rc = = - 1 | | princ = = NULL ) {
2016-03-02 11:33:04 +01:00
SAFE_FREE ( * service ) ;
SAFE_FREE ( * hostname ) ;
2014-09-23 14:09:41 +02:00
status = ADS_ERROR ( LDAP_PARAM_ERROR ) ;
goto out ;
2011-02-11 11:14:27 +01:00
}
2016-03-02 11:33:04 +01:00
* principal = princ ;
2011-02-11 11:14:27 +01:00
2014-09-23 14:09:41 +02:00
status = ADS_SUCCESS ;
out :
TALLOC_FREE ( frame ) ;
return status ;
2011-02-11 11:14:27 +01:00
}
2007-07-31 09:31:47 +00:00
static ADS_STATUS ads_generate_service_principal ( ADS_STRUCT * ads ,
struct ads_service_principal * p )
{
ADS_STATUS status ;
2012-02-13 11:23:15 +11:00
# ifdef HAVE_KRB5
2007-07-31 09:31:47 +00:00
gss_buffer_desc input_name ;
2007-09-13 15:59:46 +00:00
/* GSS_KRB5_NT_PRINCIPAL_NAME */
gss_OID_desc nt_principal =
2011-05-05 14:36:55 -07:00
{ 10 , discard_const_p ( char , " \x2a \x86 \x48 \x86 \xf7 \x12 \x01 \x02 \x02 \x01 " ) } ;
2015-04-18 08:40:14 -07:00
uint32_t minor_status ;
2007-07-31 09:31:47 +00:00
int gss_rc ;
# endif
ZERO_STRUCTP ( p ) ;
2016-03-02 11:33:04 +01:00
status = ads_guess_target ( ads ,
& p - > service ,
& p - > hostname ,
& p - > string ) ;
2016-03-02 11:31:01 +01:00
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
2007-07-31 09:31:47 +00:00
}
2012-02-13 11:23:15 +11:00
# ifdef HAVE_KRB5
2007-09-13 15:59:46 +00:00
input_name . value = p - > string ;
input_name . length = strlen ( p - > string ) ;
2007-07-31 09:31:47 +00:00
gss_rc = gss_import_name ( & minor_status , & input_name , & nt_principal , & p - > name ) ;
if ( gss_rc ) {
ads_free_service_principal ( p ) ;
return ADS_ERROR_GSS ( gss_rc , minor_status ) ;
}
# endif
2007-09-13 15:59:46 +00:00
return ADS_SUCCESS ;
2007-07-31 09:31:47 +00:00
}
2007-09-11 23:21:50 +00:00
# endif /* HAVE_KRB5 */
2002-09-25 15:19:00 +00:00
/*
this performs a SASL / SPNEGO bind
*/
static ADS_STATUS ads_sasl_spnego_bind ( ADS_STRUCT * ads )
{
2016-03-02 11:42:51 +01:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2016-03-15 20:34:27 +01:00
struct ads_service_principal p = { 0 } ;
2002-09-25 15:19:00 +00:00
struct berval * scred = NULL ;
int rc , i ;
ADS_STATUS status ;
2016-07-03 22:51:56 +03:00
DATA_BLOB blob = data_blob_null ;
2007-07-31 09:31:47 +00:00
char * given_principal = NULL ;
2002-09-25 15:19:00 +00:00
char * OIDs [ ASN1_MAX_OIDS ] ;
2005-03-22 15:12:50 +00:00
# ifdef HAVE_KRB5
2007-10-18 17:40:25 -07:00
bool got_kerberos_mechanism = False ;
2005-03-22 15:12:50 +00:00
# endif
2002-09-25 15:19:00 +00:00
2007-07-16 11:08:00 +00:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSS-SPNEGO " , NULL , NULL , NULL , & scred ) ;
2002-09-25 15:19:00 +00:00
if ( rc ! = LDAP_SASL_BIND_IN_PROGRESS ) {
status = ADS_ERROR ( rc ) ;
2016-03-02 11:42:51 +01:00
goto done ;
2002-09-25 15:19:00 +00:00
}
blob = data_blob ( scred - > bv_val , scred - > bv_len ) ;
2004-01-08 08:19:18 +00:00
ber_bvfree ( scred ) ;
2002-09-25 15:19:00 +00:00
#if 0
file_save ( " sasl_spnego.dat " , blob . data , blob . length ) ;
2001-12-08 11:18:56 +00:00
# endif
2002-09-25 15:19:00 +00:00
/* the server sent us the first part of the SPNEGO exchange in the negprot
reply */
2010-09-23 21:44:24 -07:00
if ( ! spnego_parse_negTokenInit ( talloc_tos ( ) , blob , OIDs , & given_principal , NULL ) | |
OIDs [ 0 ] = = NULL ) {
2002-09-25 15:19:00 +00:00
status = ADS_ERROR ( LDAP_OPERATIONS_ERROR ) ;
2016-03-02 11:42:51 +01:00
goto done ;
2002-09-25 15:19:00 +00:00
}
2016-03-02 11:31:01 +01:00
TALLOC_FREE ( given_principal ) ;
2002-09-25 15:19:00 +00:00
/* make sure the server understands kerberos */
for ( i = 0 ; OIDs [ i ] ; i + + ) {
2004-07-07 18:12:09 +00:00
DEBUG ( 3 , ( " ads_sasl_spnego_bind: got OID=%s \n " , OIDs [ i ] ) ) ;
2005-03-22 15:12:50 +00:00
# ifdef HAVE_KRB5
2002-09-25 15:19:00 +00:00
if ( strcmp ( OIDs [ i ] , OID_KERBEROS5_OLD ) = = 0 | |
strcmp ( OIDs [ i ] , OID_KERBEROS5 ) = = 0 ) {
got_kerberos_mechanism = True ;
}
2005-03-22 15:12:50 +00:00
# endif
2008-10-22 14:06:08 +02:00
talloc_free ( OIDs [ i ] ) ;
2002-09-25 15:19:00 +00:00
}
2001-12-08 11:18:56 +00:00
2016-03-02 11:42:51 +01:00
status = ads_generate_service_principal ( ads , & p ) ;
if ( ! ADS_ERR_OK ( status ) ) {
goto done ;
}
2002-10-01 18:26:00 +00:00
# ifdef HAVE_KRB5
2002-09-25 15:19:00 +00:00
if ( ! ( ads - > auth . flags & ADS_AUTH_DISABLE_KERBEROS ) & &
2007-02-10 20:29:09 +00:00
got_kerberos_mechanism )
{
2016-07-06 12:44:11 +02:00
const char * ccache_name = " MEMORY:ads_sasl_spnego_bind " ;
if ( ads - > auth . ccache_name ! = NULL ) {
ccache_name = ads - > auth . ccache_name ;
2004-05-06 23:08:56 +00:00
}
2004-01-08 08:19:18 +00:00
2016-07-06 12:44:11 +02:00
if ( ads - > auth . password = = NULL | |
ads - > auth . password [ 0 ] = = ' \0 ' )
{
status = ads_sasl_spnego_gensec_bind ( ads , " GSS-SPNEGO " ,
CRED_MUST_USE_KERBEROS ,
p . service , p . hostname ,
blob ) ;
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 17:02:39 +00:00
2016-07-06 12:44:11 +02:00
setenv ( KRB5_ENV_CCNAME , ccache_name , 1 ) ;
2004-01-08 08:19:18 +00:00
status = ADS_ERROR_KRB5 ( ads_kinit_password ( ads ) ) ;
if ( ADS_ERR_OK ( status ) ) {
2016-03-02 11:42:51 +01:00
status = ads_sasl_spnego_gensec_bind ( ads , " GSS-SPNEGO " ,
CRED_MUST_USE_KERBEROS ,
p . service , p . hostname ,
blob ) ;
2007-09-26 01:02:52 +00:00
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 0 , ( " kinit succeeded but "
2016-03-02 11:42:51 +01:00
" ads_sasl_spnego_gensec_bind(KRB5) failed: %s \n " ,
2007-09-26 01:02:52 +00:00
ads_errstr ( status ) ) ) ;
}
2003-04-24 14:07:13 +00:00
}
2004-01-08 08:19:18 +00:00
2003-06-10 03:47:42 +00:00
/* only fallback to NTLMSSP if allowed */
if ( ADS_ERR_OK ( status ) | |
! ( ads - > auth . flags & ADS_AUTH_ALLOW_NTLMSSP ) ) {
2016-03-02 11:42:51 +01:00
goto done ;
2003-06-10 03:47:42 +00:00
}
2007-07-31 09:31:47 +00:00
}
2016-03-02 11:31:01 +01:00
# endif
2004-05-06 23:08:56 +00:00
2002-09-25 15:19:00 +00:00
/* lets do NTLMSSP ... this has the big advantage that we don't need
to sync clocks , and we don ' t rely on special versions of the krb5
library for HMAC_MD4 encryption */
2016-03-02 11:42:51 +01:00
status = ads_sasl_spnego_gensec_bind ( ads , " GSS-SPNEGO " ,
CRED_DONT_USE_KERBEROS ,
p . service , p . hostname ,
data_blob_null ) ;
done :
ads_free_service_principal ( & p ) ;
TALLOC_FREE ( frame ) ;
2016-07-03 22:51:56 +03:00
if ( blob . data ! = NULL ) {
data_blob_free ( & blob ) ;
}
2002-09-25 15:19:00 +00:00
return status ;
}
2012-02-13 11:23:15 +11:00
# ifdef HAVE_KRB5
2001-12-08 11:18:56 +00:00
# define MAX_GSS_PASSES 3
/* this performs a SASL/gssapi bind
we avoid using cyrus - sasl to make Samba more robust . cyrus - sasl
is very dependent on correctly configured DNS whereas
this routine is much less fragile
2002-09-25 15:19:00 +00:00
see RFC2078 and RFC2222 for details
2001-12-08 11:18:56 +00:00
*/
2007-07-31 09:49:14 +00:00
static ADS_STATUS ads_sasl_gssapi_do_bind ( ADS_STRUCT * ads , const gss_name_t serv_name )
2001-12-08 11:18:56 +00:00
{
2015-04-18 08:40:14 -07:00
uint32_t minor_status ;
2012-09-07 14:14:08 -04:00
gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL ;
2007-04-04 14:50:39 +00:00
gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT ;
2001-12-08 11:18:56 +00:00
gss_OID mech_type = GSS_C_NULL_OID ;
gss_buffer_desc output_token , input_token ;
2015-04-18 08:40:14 -07:00
uint32_t req_flags , ret_flags ;
2007-07-18 08:19:13 +00:00
int conf_state ;
2001-12-08 11:18:56 +00:00
struct berval cred ;
2004-05-06 23:08:56 +00:00
struct berval * scred = NULL ;
2001-12-08 11:18:56 +00:00
int i = 0 ;
2001-12-19 12:21:12 +00:00
int gss_rc , rc ;
2015-04-18 08:40:14 -07:00
uint8_t * p ;
uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED ;
uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN ;
2001-12-19 12:21:12 +00:00
ADS_STATUS status ;
2001-12-08 11:18:56 +00:00
input_token . value = NULL ;
input_token . length = 0 ;
2012-09-07 14:14:08 -04:00
status = ads_init_gssapi_cred ( ads , & gss_cred ) ;
if ( ! ADS_ERR_OK ( status ) ) {
goto failed ;
}
2007-08-02 17:41:47 +00:00
/*
* Note : here we always ask the gssapi for sign and seal
* as this is negotiated later after the mutal
* authentication
*/
req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG ;
2007-07-18 08:19:13 +00:00
2001-12-08 11:18:56 +00:00
for ( i = 0 ; i < MAX_GSS_PASSES ; i + + ) {
gss_rc = gss_init_sec_context ( & minor_status ,
2012-09-07 14:14:08 -04:00
gss_cred ,
2001-12-08 11:18:56 +00:00
& context_handle ,
serv_name ,
mech_type ,
2007-07-18 08:19:13 +00:00
req_flags ,
2001-12-08 11:18:56 +00:00
0 ,
NULL ,
& input_token ,
NULL ,
& output_token ,
& ret_flags ,
NULL ) ;
2007-08-02 15:11:37 +00:00
if ( scred ) {
ber_bvfree ( scred ) ;
scred = NULL ;
2001-12-08 11:18:56 +00:00
}
2001-12-19 08:44:23 +00:00
if ( gss_rc & & gss_rc ! = GSS_S_CONTINUE_NEEDED ) {
2001-12-19 12:21:12 +00:00
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
2001-12-19 08:44:23 +00:00
}
2001-12-08 11:18:56 +00:00
2006-09-04 19:47:48 +00:00
cred . bv_val = ( char * ) output_token . value ;
2001-12-08 11:18:56 +00:00
cred . bv_len = output_token . length ;
2007-07-16 11:08:00 +00:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSSAPI " , & cred , NULL , NULL ,
2001-12-08 11:18:56 +00:00
& scred ) ;
2001-12-19 12:21:12 +00:00
if ( rc ! = LDAP_SASL_BIND_IN_PROGRESS ) {
status = ADS_ERROR ( rc ) ;
goto failed ;
}
2001-12-08 11:18:56 +00:00
if ( output_token . value ) {
gss_release_buffer ( & minor_status , & output_token ) ;
}
if ( scred ) {
input_token . value = scred - > bv_val ;
input_token . length = scred - > bv_len ;
} else {
input_token . value = NULL ;
input_token . length = 0 ;
}
2001-12-19 12:21:12 +00:00
if ( gss_rc = = 0 ) break ;
2001-12-08 11:18:56 +00:00
}
gss_rc = gss_unwrap ( & minor_status , context_handle , & input_token , & output_token ,
2007-07-18 08:19:13 +00:00
& conf_state , NULL ) ;
2007-08-02 15:11:37 +00:00
if ( scred ) {
ber_bvfree ( scred ) ;
scred = NULL ;
}
2001-12-19 12:21:12 +00:00
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
2001-12-08 11:18:56 +00:00
2015-04-18 08:40:14 -07:00
p = ( uint8_t * ) output_token . value ;
2001-12-08 11:18:56 +00:00
2006-02-03 22:19:41 +00:00
#if 0
2002-09-25 15:19:00 +00:00
file_save ( " sasl_gssapi.dat " , output_token . value , output_token . length ) ;
2006-02-03 22:19:41 +00:00
# endif
2006-08-29 00:53:28 +00:00
if ( p ) {
2007-08-02 17:41:47 +00:00
wrap_type = CVAL ( p , 0 ) ;
SCVAL ( p , 0 , 0 ) ;
max_msg_size = RIVAL ( p , 0 ) ;
2006-08-29 00:53:28 +00:00
}
2001-12-08 11:18:56 +00:00
gss_release_buffer ( & minor_status , & output_token ) ;
2007-08-02 17:41:47 +00:00
if ( ! ( wrap_type & ads - > ldap . wrap_type ) ) {
/*
* the server doesn ' t supports the wrap
* type we want : - (
*/
DEBUG ( 0 , ( " The ldap sasl wrap type doesn't match wanted[%d] server[%d] \n " ,
ads - > ldap . wrap_type , wrap_type ) ) ;
DEBUGADD ( 0 , ( " You may want to set the 'client ldap sasl wrapping' option \n " ) ) ;
status = ADS_ERROR_NT ( NT_STATUS_NOT_SUPPORTED ) ;
goto failed ;
}
/* 0x58 is the minimum windows accepts */
if ( max_msg_size < 0x58 ) {
max_msg_size = 0x58 ;
}
2007-04-10 16:04:22 +00:00
output_token . length = 4 ;
output_token . value = SMB_MALLOC ( output_token . length ) ;
2010-09-09 15:29:03 -07:00
if ( ! output_token . value ) {
output_token . length = 0 ;
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
goto failed ;
}
2015-04-18 08:40:14 -07:00
p = ( uint8_t * ) output_token . value ;
2001-12-08 11:18:56 +00:00
2007-08-02 17:41:47 +00:00
RSIVAL ( p , 0 , max_msg_size ) ;
SCVAL ( p , 0 , ads - > ldap . wrap_type ) ;
2007-04-10 16:04:22 +00:00
/*
* we used to add sprintf ( " dn:%s " , ads - > config . bind_path ) here .
* but using ads - > config . bind_path is the wrong ! It should be
* the DN of the user object !
*
* w2k3 gives an error when we send an incorrect DN , but sending nothing
* is ok and matches the information flow used in GSS - SPNEGO .
*/
2001-12-08 11:18:56 +00:00
2001-12-19 12:21:12 +00:00
gss_rc = gss_wrap ( & minor_status , context_handle , 0 , GSS_C_QOP_DEFAULT ,
2010-09-09 15:29:03 -07:00
& output_token , /* used as *input* here. */
& conf_state ,
& input_token ) ; /* Used as *output* here. */
2001-12-19 12:21:12 +00:00
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
2010-09-09 15:29:03 -07:00
output_token . length = 0 ;
SAFE_FREE ( output_token . value ) ;
2001-12-19 12:21:12 +00:00
goto failed ;
}
2001-12-08 11:18:56 +00:00
2010-09-09 15:29:03 -07:00
/* We've finished with output_token. */
SAFE_FREE ( output_token . value ) ;
output_token . length = 0 ;
2001-12-08 11:18:56 +00:00
2006-09-04 19:47:48 +00:00
cred . bv_val = ( char * ) input_token . value ;
2001-12-08 11:18:56 +00:00
cred . bv_len = input_token . length ;
2007-07-16 11:08:00 +00:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSSAPI " , & cred , NULL , NULL ,
2001-12-08 11:18:56 +00:00
& scred ) ;
gss_release_buffer ( & minor_status , & input_token ) ;
2007-07-25 07:23:20 +00:00
status = ADS_ERROR ( rc ) ;
if ( ! ADS_ERR_OK ( status ) ) {
goto failed ;
}
2001-12-08 11:18:56 +00:00
2007-07-18 08:19:13 +00:00
if ( ads - > ldap . wrap_type > ADS_SASLWRAP_TYPE_PLAIN ) {
gss_rc = gss_wrap_size_limit ( & minor_status , context_handle ,
( ads - > ldap . wrap_type = = ADS_SASLWRAP_TYPE_SEAL ) ,
GSS_C_QOP_DEFAULT ,
2007-08-02 17:41:47 +00:00
max_msg_size , & ads - > ldap . out . max_unwrapped ) ;
2007-07-18 08:19:13 +00:00
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
2007-08-02 17:41:47 +00:00
ads - > ldap . out . sig_size = max_msg_size - ads - > ldap . out . max_unwrapped ;
ads - > ldap . in . min_wrapped = 0x2C ; /* taken from a capture with LDAP unbind */
2016-04-22 16:31:55 +02:00
ads - > ldap . in . max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED ;
2007-07-31 12:27:25 +00:00
status = ads_setup_sasl_wrapping ( ads , & ads_sasl_gssapi_ops , context_handle ) ;
if ( ! ADS_ERR_OK ( status ) ) {
2007-07-31 12:30:37 +00:00
DEBUG ( 0 , ( " ads_setup_sasl_wrapping() failed: %s \n " ,
2007-07-31 12:27:25 +00:00
ads_errstr ( status ) ) ) ;
goto failed ;
}
2007-07-18 08:19:13 +00:00
/* make sure we don't free context_handle */
context_handle = GSS_C_NO_CONTEXT ;
}
2007-08-02 17:41:47 +00:00
2001-12-08 11:18:56 +00:00
failed :
2012-09-07 14:14:08 -04:00
if ( gss_cred ! = GSS_C_NO_CREDENTIAL )
gss_release_cred ( & minor_status , & gss_cred ) ;
2007-04-04 14:50:39 +00:00
if ( context_handle ! = GSS_C_NO_CONTEXT )
2007-04-04 17:38:12 +00:00
gss_delete_sec_context ( & minor_status , & context_handle , GSS_C_NO_BUFFER ) ;
2007-03-15 22:11:13 +00:00
2004-05-06 23:08:56 +00:00
if ( scred )
ber_bvfree ( scred ) ;
2001-12-19 12:21:12 +00:00
return status ;
2001-12-08 11:18:56 +00:00
}
2007-07-31 09:49:14 +00:00
static ADS_STATUS ads_sasl_gssapi_bind ( ADS_STRUCT * ads )
{
ADS_STATUS status ;
struct ads_service_principal p ;
2016-07-06 12:48:11 +02:00
const char * ccache_name = " MEMORY:ads_sasl_gssapi_do_bind " ;
2007-07-31 09:49:14 +00:00
2016-03-02 11:31:01 +01:00
status = ads_generate_service_principal ( ads , & p ) ;
2007-07-31 09:49:14 +00:00
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
2016-07-06 12:48:11 +02:00
if ( ads - > auth . password = = NULL | |
ads - > auth . password [ 0 ] = = ' \0 ' ) {
status = ads_sasl_gssapi_do_bind ( ads , p . name ) ;
if ( ADS_ERR_OK ( status ) ) {
ads_free_service_principal ( & p ) ;
return status ;
}
2007-07-31 09:49:14 +00:00
2016-07-06 12:48:11 +02:00
DEBUG ( 10 , ( " ads_sasl_gssapi_do_bind failed with: %s, "
" calling kinit \n " , ads_errstr ( status ) ) ) ;
}
2007-07-31 09:49:14 +00:00
2016-07-06 12:48:11 +02:00
if ( ads - > auth . ccache_name ! = NULL ) {
ccache_name = ads - > auth . ccache_name ;
}
setenv ( KRB5_ENV_CCNAME , ccache_name , 1 ) ;
2007-07-31 09:49:14 +00:00
status = ADS_ERROR_KRB5 ( ads_kinit_password ( ads ) ) ;
if ( ADS_ERR_OK ( status ) ) {
status = ads_sasl_gssapi_do_bind ( ads , p . name ) ;
}
ads_free_service_principal ( & p ) ;
return status ;
}
2012-02-13 11:23:15 +11:00
# endif /* HAVE_KRB5 */
2002-09-25 15:19:00 +00:00
/* mapping between SASL mechanisms and functions */
static struct {
const char * name ;
ADS_STATUS ( * fn ) ( ADS_STRUCT * ) ;
} sasl_mechanisms [ ] = {
{ " GSS-SPNEGO " , ads_sasl_spnego_bind } ,
2012-02-13 11:23:15 +11:00
# ifdef HAVE_KRB5
2002-09-25 15:19:00 +00:00
{ " GSSAPI " , ads_sasl_gssapi_bind } , /* doesn't work with .NET RC1. No idea why */
# endif
{ NULL , NULL }
} ;
2001-12-08 11:18:56 +00:00
2001-12-19 12:21:12 +00:00
ADS_STATUS ads_sasl_bind ( ADS_STRUCT * ads )
2001-12-08 11:18:56 +00:00
{
2002-09-25 15:19:00 +00:00
const char * attrs [ ] = { " supportedSASLMechanisms " , NULL } ;
char * * values ;
ADS_STATUS status ;
int i , j ;
2006-09-03 21:07:16 +00:00
LDAPMessage * res ;
2002-09-25 15:19:00 +00:00
/* get a list of supported SASL mechanisms */
status = ads_do_search ( ads , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
2007-07-16 11:08:00 +00:00
values = ldap_get_values ( ads - > ldap . ld , res , " supportedSASLMechanisms " ) ;
2002-09-25 15:19:00 +00:00
2007-07-18 07:45:16 +00:00
if ( ads - > auth . flags & ADS_AUTH_SASL_SEAL ) {
ads - > ldap . wrap_type = ADS_SASLWRAP_TYPE_SEAL ;
} else if ( ads - > auth . flags & ADS_AUTH_SASL_SIGN ) {
ads - > ldap . wrap_type = ADS_SASLWRAP_TYPE_SIGN ;
} else {
ads - > ldap . wrap_type = ADS_SASLWRAP_TYPE_PLAIN ;
}
2002-09-25 15:19:00 +00:00
/* try our supported mechanisms in order */
for ( i = 0 ; sasl_mechanisms [ i ] . name ; i + + ) {
/* see if the server supports it */
for ( j = 0 ; values & & values [ j ] ; j + + ) {
if ( strcmp ( values [ j ] , sasl_mechanisms [ i ] . name ) = = 0 ) {
DEBUG ( 4 , ( " Found SASL mechanism %s \n " , values [ j ] ) ) ;
2010-03-30 09:50:09 +02:00
retry :
2002-09-25 15:19:00 +00:00
status = sasl_mechanisms [ i ] . fn ( ads ) ;
2010-03-30 09:50:09 +02:00
if ( status . error_type = = ENUM_ADS_ERROR_LDAP & &
status . err . rc = = LDAP_STRONG_AUTH_REQUIRED & &
ads - > ldap . wrap_type = = ADS_SASLWRAP_TYPE_PLAIN )
{
DEBUG ( 3 , ( " SASL bin got LDAP_STRONG_AUTH_REQUIRED "
" retrying with signing enabled \n " ) ) ;
ads - > ldap . wrap_type = ADS_SASLWRAP_TYPE_SIGN ;
goto retry ;
}
2002-09-25 15:19:00 +00:00
ldap_value_free ( values ) ;
ldap_msgfree ( res ) ;
return status ;
}
}
}
ldap_value_free ( values ) ;
ldap_msgfree ( res ) ;
return ADS_ERROR ( LDAP_AUTH_METHOD_NOT_SUPPORTED ) ;
2001-12-08 11:18:56 +00:00
}
2006-01-25 21:25:25 +00:00
# endif /* HAVE_LDAP */
2001-12-08 11:18:56 +00:00