2001-12-08 14:18:56 +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
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 .
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 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"
2002-10-01 22:26:00 +04:00
# ifdef HAVE_LDAP
2001-12-08 14:18:56 +03:00
2007-07-18 12:15:42 +04:00
static ADS_STATUS ads_sasl_ntlmssp_wrap ( ADS_STRUCT * ads , uint8 * buf , uint32 len )
{
2007-07-18 16:28:32 +04:00
struct ntlmssp_state * ntlmssp_state =
( struct ntlmssp_state * ) ads - > ldap . wrap_private_data ;
2007-07-18 12:15:42 +04:00
ADS_STATUS status ;
NTSTATUS nt_status ;
DATA_BLOB sig ;
uint8 * dptr = ads - > ldap . out . buf + ( 4 + NTLMSSP_SIG_SIZE ) ;
/* copy the data to the right location */
memcpy ( dptr , buf , len ) ;
/* create the signature and may encrypt the data */
if ( ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_SEAL ) {
nt_status = ntlmssp_seal_packet ( ntlmssp_state ,
dptr , len ,
dptr , len ,
& sig ) ;
} else {
nt_status = ntlmssp_sign_packet ( ntlmssp_state ,
dptr , len ,
dptr , len ,
& sig ) ;
}
status = ADS_ERROR_NT ( nt_status ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
/* copy the signature to the right location */
memcpy ( ads - > ldap . out . buf + 4 ,
sig . data , NTLMSSP_SIG_SIZE ) ;
data_blob_free ( & sig ) ;
/* set how many bytes must be written to the underlying socket */
ads - > ldap . out . left = 4 + NTLMSSP_SIG_SIZE + len ;
return ADS_SUCCESS ;
}
static ADS_STATUS ads_sasl_ntlmssp_unwrap ( ADS_STRUCT * ads )
{
2007-07-18 16:28:32 +04:00
struct ntlmssp_state * ntlmssp_state =
( struct ntlmssp_state * ) ads - > ldap . wrap_private_data ;
2007-07-18 12:15:42 +04:00
ADS_STATUS status ;
NTSTATUS nt_status ;
DATA_BLOB sig ;
uint8 * dptr = ads - > ldap . in . buf + ( 4 + NTLMSSP_SIG_SIZE ) ;
uint32 dlen = ads - > ldap . in . ofs - ( 4 + NTLMSSP_SIG_SIZE ) ;
/* wrap the signature into a DATA_BLOB */
sig = data_blob_const ( ads - > ldap . in . buf + 4 , NTLMSSP_SIG_SIZE ) ;
/* verify the signature and maybe decrypt the data */
if ( ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_SEAL ) {
nt_status = ntlmssp_unseal_packet ( ntlmssp_state ,
dptr , dlen ,
dptr , dlen ,
& sig ) ;
} else {
nt_status = ntlmssp_check_packet ( ntlmssp_state ,
dptr , dlen ,
dptr , dlen ,
& sig ) ;
}
status = ADS_ERROR_NT ( nt_status ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
/* set the amount of bytes for the upper layer and set the ofs to the data */
ads - > ldap . in . left = dlen ;
ads - > ldap . in . ofs = 4 + NTLMSSP_SIG_SIZE ;
return ADS_SUCCESS ;
}
static void ads_sasl_ntlmssp_disconnect ( ADS_STRUCT * ads )
{
2007-07-18 16:28:32 +04:00
struct ntlmssp_state * ntlmssp_state =
( struct ntlmssp_state * ) ads - > ldap . wrap_private_data ;
2007-07-18 12:15:42 +04:00
ntlmssp_end ( & ntlmssp_state ) ;
ads - > ldap . wrap_ops = NULL ;
ads - > ldap . wrap_private_data = NULL ;
}
static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
. name = " ntlmssp " ,
. wrap = ads_sasl_ntlmssp_wrap ,
. unwrap = ads_sasl_ntlmssp_unwrap ,
. disconnect = ads_sasl_ntlmssp_disconnect
} ;
2002-09-25 19:19:00 +04:00
/*
perform a LDAP / SASL / SPNEGO / NTLMSSP bind ( just how many layers can
we fit on one socket ? ? )
2001-12-08 14:18:56 +03:00
*/
2002-09-25 19:19:00 +04:00
static ADS_STATUS ads_sasl_spnego_ntlmssp_bind ( ADS_STRUCT * ads )
2001-12-08 14:18:56 +03:00
{
2007-05-14 16:16:20 +04:00
DATA_BLOB msg1 = data_blob_null ;
DATA_BLOB blob = data_blob_null ;
DATA_BLOB blob_in = data_blob_null ;
DATA_BLOB blob_out = data_blob_null ;
2004-05-07 03:08:56 +04:00
struct berval cred , * scred = 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 ;
2005-11-04 20:39:42 +03:00
int turn = 1 ;
2007-07-18 12:15:42 +04:00
uint32 features = 0 ;
2001-12-08 14:18:56 +03:00
2005-11-04 20:39:42 +03:00
struct ntlmssp_state * ntlmssp_state ;
2002-09-25 19:19:00 +04:00
2005-11-04 20:39:42 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status = ntlmssp_client_start ( & ntlmssp_state ) ) ) {
return ADS_ERROR_NT ( nt_status ) ;
2002-09-25 19:19:00 +04:00
}
2007-01-30 00:15:25 +03:00
ntlmssp_state - > neg_flags & = ~ NTLMSSP_NEGOTIATE_SIGN ;
2002-09-25 19:19:00 +04:00
2005-11-04 20:39:42 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status = ntlmssp_set_username ( ntlmssp_state , ads - > auth . user_name ) ) ) {
return ADS_ERROR_NT ( nt_status ) ;
}
if ( ! NT_STATUS_IS_OK ( nt_status = ntlmssp_set_domain ( ntlmssp_state , ads - > auth . realm ) ) ) {
return ADS_ERROR_NT ( nt_status ) ;
}
if ( ! NT_STATUS_IS_OK ( nt_status = ntlmssp_set_password ( ntlmssp_state , ads - > auth . password ) ) ) {
return ADS_ERROR_NT ( nt_status ) ;
2002-09-25 19:19:00 +04:00
}
2007-07-18 12:15:42 +04:00
switch ( ads - > ldap . wrap_type ) {
case ADS_SASLWRAP_TYPE_SEAL :
features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL ;
break ;
case ADS_SASLWRAP_TYPE_SIGN :
if ( ads - > auth . flags & ADS_AUTH_SASL_FORCE ) {
features = NTLMSSP_FEATURE_SIGN ;
} else {
/*
* windows servers are broken with sign only ,
* so we need to use seal here too
*/
features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL ;
ads - > ldap . wrap_type = ADS_SASLWRAP_TYPE_SEAL ;
}
break ;
case ADS_SASLWRAP_TYPE_PLAIN :
break ;
}
ntlmssp_want_feature ( ntlmssp_state , features ) ;
2007-05-14 16:16:20 +04:00
blob_in = data_blob_null ;
2005-11-04 20:39:42 +03:00
do {
nt_status = ntlmssp_update ( ntlmssp_state ,
blob_in , & blob_out ) ;
data_blob_free ( & blob_in ) ;
if ( ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_MORE_PROCESSING_REQUIRED )
| | NT_STATUS_IS_OK ( nt_status ) )
& & blob_out . length ) {
if ( turn = = 1 ) {
/* and wrap it in a SPNEGO wrapper */
msg1 = gen_negTokenInit ( OID_NTLMSSP , blob_out ) ;
} else {
/* wrap it in SPNEGO */
msg1 = spnego_gen_auth ( blob_out ) ;
}
data_blob_free ( & blob_out ) ;
cred . bv_val = ( char * ) msg1 . data ;
cred . bv_len = msg1 . length ;
scred = NULL ;
2007-07-16 15:08:00 +04:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSS-SPNEGO " , & cred , NULL , NULL , & scred ) ;
2005-11-04 20:39:42 +03:00
data_blob_free ( & msg1 ) ;
if ( ( rc ! = LDAP_SASL_BIND_IN_PROGRESS ) & & ( rc ! = 0 ) ) {
if ( scred ) {
ber_bvfree ( scred ) ;
}
ntlmssp_end ( & ntlmssp_state ) ;
return ADS_ERROR ( rc ) ;
}
if ( scred ) {
blob = data_blob ( scred - > bv_val , scred - > bv_len ) ;
ber_bvfree ( scred ) ;
} else {
2007-05-14 16:16:20 +04:00
blob = data_blob_null ;
2005-11-04 20:39:42 +03:00
}
} else {
ntlmssp_end ( & ntlmssp_state ) ;
data_blob_free ( & blob_out ) ;
return ADS_ERROR_NT ( nt_status ) ;
}
if ( ( turn = = 1 ) & &
( rc = = LDAP_SASL_BIND_IN_PROGRESS ) ) {
2007-05-14 16:16:20 +04:00
DATA_BLOB tmp_blob = data_blob_null ;
2005-11-04 20:39:42 +03:00
/* the server might give us back two challenges */
if ( ! spnego_parse_challenge ( blob , & blob_in ,
& tmp_blob ) ) {
ntlmssp_end ( & ntlmssp_state ) ;
data_blob_free ( & blob ) ;
DEBUG ( 3 , ( " Failed to parse challenges \n " ) ) ;
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
}
data_blob_free ( & tmp_blob ) ;
} else if ( rc = = LDAP_SASL_BIND_IN_PROGRESS ) {
2007-04-05 16:30:23 +04:00
if ( ! spnego_parse_auth_response ( blob , nt_status , OID_NTLMSSP ,
2005-11-04 20:39:42 +03:00
& blob_in ) ) {
ntlmssp_end ( & ntlmssp_state ) ;
data_blob_free ( & blob ) ;
DEBUG ( 3 , ( " Failed to parse auth response \n " ) ) ;
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
}
}
data_blob_free ( & blob ) ;
data_blob_free ( & blob_out ) ;
turn + + ;
} while ( rc = = LDAP_SASL_BIND_IN_PROGRESS & & ! NT_STATUS_IS_OK ( nt_status ) ) ;
2004-05-07 03:08:56 +04:00
2005-11-04 20:39:42 +03:00
/* we have a reference conter on ntlmssp_state, if we are signing
then the state will be kept by the signing engine */
2002-09-25 19:19:00 +04:00
2007-07-18 12:15:42 +04:00
if ( ads - > ldap . wrap_type > ADS_SASLWRAP_TYPE_PLAIN ) {
ads - > ldap . out . min = 4 ;
ads - > ldap . out . max = 0x0FFFFFFF - NTLMSSP_SIG_SIZE ;
ads - > ldap . out . sig_size = NTLMSSP_SIG_SIZE ;
ads - > ldap . in . min = 4 ;
ads - > ldap . in . max = 0x0FFFFFFF ;
2007-07-31 16:27:25 +04:00
status = ads_setup_sasl_wrapping ( ads , & ads_sasl_ntlmssp_ops , ntlmssp_state ) ;
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 ) ) ) ;
ntlmssp_end ( & ntlmssp_state ) ;
return status ;
}
2007-07-18 12:15:42 +04:00
} else {
ntlmssp_end ( & ntlmssp_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
2007-07-18 12:19:13 +04:00
# ifdef HAVE_GSSAPI
static ADS_STATUS ads_sasl_gssapi_wrap ( ADS_STRUCT * ads , uint8 * buf , uint32 len )
{
gss_ctx_id_t context_handle = ads - > ldap . wrap_private_data ;
ADS_STATUS status ;
int gss_rc ;
uint32 minor_status ;
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 )
{
gss_ctx_id_t context_handle = ads - > ldap . wrap_private_data ;
ADS_STATUS status ;
int gss_rc ;
uint32 minor_status ;
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 ) ;
}
if ( wrapped . length < wrapped . length ) {
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 )
{
gss_ctx_id_t context_handle = ads - > ldap . wrap_private_data ;
uint32 minor_status ;
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 14:34:16 +04:00
/*
perform a LDAP / SASL / SPNEGO / GSSKRB5 bind
*/
2007-07-31 13:31:47 +04:00
static ADS_STATUS ads_sasl_spnego_gsskrb5_bind ( ADS_STRUCT * ads , const gss_name_t serv_name )
2007-07-25 14:34:16 +04:00
{
ADS_STATUS status ;
BOOL ok ;
uint32 minor_status ;
int gss_rc , rc ;
gss_OID_desc krb5_mech_type =
{ 9 , CONST_DISCARD ( char * , " \x2a \x86 \x48 \x86 \xf7 \x12 \x01 \x02 \x02 " ) } ;
gss_OID mech_type = & krb5_mech_type ;
gss_OID actual_mech_type = GSS_C_NULL_OID ;
const char * spnego_mechs [ ] = { OID_KERBEROS5_OLD , OID_KERBEROS5 , OID_NTLMSSP , NULL } ;
gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT ;
gss_buffer_desc input_token , output_token ;
uint32 req_flags , ret_flags ;
uint32 req_tmp , ret_tmp ;
DATA_BLOB unwrapped ;
DATA_BLOB wrapped ;
struct berval cred , * scred = NULL ;
input_token . value = NULL ;
input_token . length = 0 ;
req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG ;
switch ( ads - > ldap . wrap_type ) {
case ADS_SASLWRAP_TYPE_SEAL :
req_flags | = GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG ;
break ;
case ADS_SASLWRAP_TYPE_SIGN :
req_flags | = GSS_C_INTEG_FLAG ;
break ;
case ADS_SASLWRAP_TYPE_PLAIN :
break ;
}
/* Note: here we explicit ask for the krb5 mech_type */
gss_rc = gss_init_sec_context ( & minor_status ,
GSS_C_NO_CREDENTIAL ,
& context_handle ,
serv_name ,
mech_type ,
req_flags ,
0 ,
NULL ,
& input_token ,
& actual_mech_type ,
& output_token ,
& ret_flags ,
NULL ) ;
if ( gss_rc & & gss_rc ! = GSS_S_CONTINUE_NEEDED ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
/*
* As some gssapi krb5 mech implementations
* automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
* to req_flags internaly , it ' s not possible to
* use plain or signing only connection via
* the gssapi interface .
*
* Because of this we need to check it the ret_flags
* has more flags as req_flags and correct the value
* of ads - > ldap . wrap_type .
*
* I ads - > auth . flags has ADS_AUTH_SASL_FORCE
* we need to give an error .
*/
req_tmp = req_flags & ( GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG ) ;
ret_tmp = ret_flags & ( GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG ) ;
if ( req_tmp = = ret_tmp ) {
/* everythings fine... */
} else if ( req_flags & GSS_C_CONF_FLAG ) {
/*
* here we wanted sealing but didn ' t got it
* from the gssapi library
*/
status = ADS_ERROR_NT ( NT_STATUS_NOT_SUPPORTED ) ;
goto failed ;
2007-07-27 11:19:36 +04:00
} else if ( ( req_flags & GSS_C_INTEG_FLAG ) & &
! ( ret_flags & GSS_C_INTEG_FLAG ) ) {
2007-07-25 14:34:16 +04:00
/*
* here we wanted siging but didn ' t got it
* from the gssapi library
*/
status = ADS_ERROR_NT ( NT_STATUS_NOT_SUPPORTED ) ;
goto failed ;
} else if ( ret_flags & GSS_C_CONF_FLAG ) {
/*
* here we didn ' t want sealing
* but the gssapi library forces it
* so correct the needed wrap_type if
* the caller didn ' t forced siging only
*/
if ( ads - > auth . flags & ADS_AUTH_SASL_FORCE ) {
status = ADS_ERROR_NT ( NT_STATUS_NOT_SUPPORTED ) ;
goto failed ;
}
ads - > ldap . wrap_type = ADS_SASLWRAP_TYPE_SEAL ;
req_flags = ret_flags ;
} else if ( ret_flags & GSS_C_INTEG_FLAG ) {
/*
* here we didn ' t want signing
* but the gssapi library forces it
* so correct the needed wrap_type if
* the caller didn ' t forced plain
*/
if ( ads - > auth . flags & ADS_AUTH_SASL_FORCE ) {
status = ADS_ERROR_NT ( NT_STATUS_NOT_SUPPORTED ) ;
goto failed ;
}
ads - > ldap . wrap_type = ADS_SASLWRAP_TYPE_SIGN ;
req_flags = ret_flags ;
} else {
/*
* This could ( should ? ) not happen
*/
status = ADS_ERROR_NT ( NT_STATUS_INTERNAL_ERROR ) ;
goto failed ;
}
/* and wrap that in a shiny SPNEGO wrapper */
unwrapped = data_blob_const ( output_token . value , output_token . length ) ;
wrapped = gen_negTokenTarg ( spnego_mechs , unwrapped ) ;
gss_release_buffer ( & minor_status , & output_token ) ;
if ( unwrapped . length > wrapped . length ) {
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
goto failed ;
}
cred . bv_val = ( char * ) wrapped . data ;
cred . bv_len = wrapped . length ;
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSS-SPNEGO " , & cred , NULL , NULL ,
& scred ) ;
data_blob_free ( & wrapped ) ;
if ( rc ! = LDAP_SUCCESS ) {
status = ADS_ERROR ( rc ) ;
goto failed ;
}
if ( scred ) {
wrapped = data_blob_const ( scred - > bv_val , scred - > bv_len ) ;
} else {
wrapped = data_blob_null ;
}
ok = spnego_parse_auth_response ( wrapped , NT_STATUS_OK ,
OID_KERBEROS5_OLD ,
& unwrapped ) ;
if ( scred ) ber_bvfree ( scred ) ;
if ( ! ok ) {
status = ADS_ERROR_NT ( NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
goto failed ;
}
input_token . value = unwrapped . data ;
input_token . length = unwrapped . length ;
/*
* As we asked for mutal authentication
* we need to pass the servers response
* to gssapi
*/
gss_rc = gss_init_sec_context ( & minor_status ,
GSS_C_NO_CREDENTIAL ,
& context_handle ,
serv_name ,
mech_type ,
req_flags ,
0 ,
NULL ,
& input_token ,
& actual_mech_type ,
& output_token ,
& ret_flags ,
NULL ) ;
data_blob_free ( & unwrapped ) ;
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
gss_release_buffer ( & minor_status , & output_token ) ;
/*
* If we the sign and seal options
* doesn ' t match after getting the response
* from the server , we don ' t want to use the connection
*/
req_tmp = req_flags & ( GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG ) ;
ret_tmp = ret_flags & ( GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG ) ;
if ( req_tmp ! = ret_tmp ) {
/* everythings fine... */
status = ADS_ERROR_NT ( NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
goto failed ;
}
if ( ads - > ldap . wrap_type > ADS_SASLWRAP_TYPE_PLAIN ) {
uint32 max_msg_size = 0x0A000000 ;
gss_rc = gss_wrap_size_limit ( & minor_status , context_handle ,
( ads - > ldap . wrap_type = = ADS_SASLWRAP_TYPE_SEAL ) ,
GSS_C_QOP_DEFAULT ,
max_msg_size , & ads - > ldap . out . max ) ;
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
ads - > ldap . out . min = 4 ;
ads - > ldap . out . sig_size = max_msg_size - ads - > ldap . out . max ;
ads - > ldap . in . min = 4 ;
ads - > ldap . in . max = max_msg_size ;
2007-07-31 16:27:25 +04:00
status = ads_setup_sasl_wrapping ( ads , & ads_sasl_gssapi_ops , context_handle ) ;
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 ) ) ) ;
goto failed ;
}
2007-07-25 14:34:16 +04:00
/* make sure we don't free context_handle */
context_handle = GSS_C_NO_CONTEXT ;
}
failed :
if ( context_handle ! = GSS_C_NO_CONTEXT )
gss_delete_sec_context ( & minor_status , & context_handle , GSS_C_NO_BUFFER ) ;
return status ;
}
2007-07-18 12:19:13 +04:00
# endif
2006-12-12 23:27:01 +03:00
# ifdef HAVE_KRB5
2007-07-31 13:31:47 +04:00
struct ads_service_principal {
krb5_context ctx ;
char * string ;
krb5_principal principal ;
# ifdef HAVE_GSSAPI
gss_name_t name ;
# endif
} ;
static void ads_free_service_principal ( struct ads_service_principal * p )
{
SAFE_FREE ( p - > string ) ;
# ifdef HAVE_GSSAPI
if ( p - > name ) {
uint32 minor_status ;
gss_release_name ( & minor_status , & p - > name ) ;
}
# endif
if ( p - > principal ) {
krb5_free_principal ( p - > ctx , p - > principal ) ;
}
if ( p - > ctx ) {
krb5_free_context ( p - > ctx ) ;
}
ZERO_STRUCTP ( p ) ;
}
static ADS_STATUS ads_generate_service_principal ( ADS_STRUCT * ads ,
const char * given_principal ,
struct ads_service_principal * p )
{
ADS_STATUS status ;
krb5_enctype enc_types [ ] = {
# ifdef ENCTYPE_ARCFOUR_HMAC
ENCTYPE_ARCFOUR_HMAC ,
# endif
ENCTYPE_DES_CBC_MD5 ,
ENCTYPE_NULL } ;
# ifdef HAVE_GSSAPI
gss_buffer_desc input_name ;
gss_OID_desc nt_principal =
{ 10 , CONST_DISCARD ( char * , " \052 \206 \110 \206 \367 \022 \001 \002 \002 \002 " ) } ;
uint32 minor_status ;
int gss_rc ;
# endif
ZERO_STRUCTP ( p ) ;
/* I've seen a child Windows 2000 domain not send
the principal name back in the first round of
the SASL bind reply . So we guess based on server
name and realm . - - jerry */
if ( given_principal ) {
p - > string = SMB_STRDUP ( given_principal ) ;
if ( ! p - > string ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
} else if ( ads - > server . realm & & ads - > server . ldap_server ) {
char * server , * server_realm ;
server = SMB_STRDUP ( ads - > server . ldap_server ) ;
server_realm = SMB_STRDUP ( ads - > server . realm ) ;
if ( ! server | | ! server_realm ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
strlower_m ( server ) ;
strupper_m ( server_realm ) ;
asprintf ( & p - > string , " ldap/%s@%s " , server , server_realm ) ;
SAFE_FREE ( server ) ;
SAFE_FREE ( server_realm ) ;
2007-07-31 13:37:25 +04:00
if ( ! p - > string ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
} else if ( ads - > config . realm & & ads - > config . ldap_server_name ) {
char * server , * server_realm ;
server = SMB_STRDUP ( ads - > config . ldap_server_name ) ;
server_realm = SMB_STRDUP ( ads - > config . realm ) ;
if ( ! server | | ! server_realm ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
strlower_m ( server ) ;
strupper_m ( server_realm ) ;
asprintf ( & p - > string , " ldap/%s@%s " , server , server_realm ) ;
SAFE_FREE ( server ) ;
SAFE_FREE ( server_realm ) ;
2007-07-31 13:31:47 +04:00
if ( ! p - > string ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
}
initialize_krb5_error_table ( ) ;
status = ADS_ERROR_KRB5 ( krb5_init_context ( & p - > ctx ) ) ;
if ( ! ADS_ERR_OK ( status ) ) {
ads_free_service_principal ( p ) ;
return status ;
}
status = ADS_ERROR_KRB5 ( krb5_set_default_tgs_ktypes ( p - > ctx , enc_types ) ) ;
if ( ! ADS_ERR_OK ( status ) ) {
ads_free_service_principal ( p ) ;
return status ;
}
status = ADS_ERROR_KRB5 ( smb_krb5_parse_name ( p - > ctx , p - > string , & p - > principal ) ) ;
if ( ! ADS_ERR_OK ( status ) ) {
ads_free_service_principal ( p ) ;
return status ;
}
# ifdef HAVE_GSSAPI
/*
* The MIT libraries have a * HORRIBLE * bug - input_value . value needs
* to point to the * address * of the krb5_principal , and the gss libraries
* to a shallow copy of the krb5_principal pointer - so we need to keep
* the krb5_principal around until we do the gss_release_name . MIT * SUCKS * !
* Just one more way in which MIT engineers screwed me over . . . . JRA .
*
* That ' s the reason for principal not beeing a local var in this function
*/
input_name . value = & p - > principal ;
input_name . length = sizeof ( p - > principal ) ;
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
return status ;
}
2002-09-25 19:19:00 +04:00
/*
perform a LDAP / SASL / SPNEGO / KRB5 bind
*/
2007-07-25 14:34:16 +04:00
static ADS_STATUS ads_sasl_spnego_rawkrb5_bind ( ADS_STRUCT * ads , const char * principal )
2002-09-25 19:19:00 +04:00
{
2007-05-14 16:16:20 +04:00
DATA_BLOB blob = data_blob_null ;
2004-05-07 03:08:56 +04:00
struct berval cred , * scred = NULL ;
2007-05-14 16:16:20 +04:00
DATA_BLOB session_key = data_blob_null ;
2002-09-25 19:19:00 +04:00
int rc ;
2007-07-25 14:34:16 +04:00
if ( ads - > ldap . wrap_type > ADS_SASLWRAP_TYPE_PLAIN ) {
return ADS_ERROR_NT ( NT_STATUS_NOT_SUPPORTED ) ;
}
2007-02-08 20:02:39 +03:00
rc = spnego_gen_negTokenTarg ( principal , ads - > auth . time_offset , & blob , & session_key , 0 ,
& ads - > auth . tgs_expire ) ;
2002-09-25 19:19:00 +04:00
2004-01-08 11:19:18 +03:00
if ( rc ) {
return ADS_ERROR_KRB5 ( rc ) ;
2002-09-25 19:19:00 +04:00
}
/* now send the auth packet and we should be done */
2003-08-15 08:42:05 +04:00
cred . bv_val = ( char * ) blob . data ;
2002-09-25 19:19:00 +04:00
cred . bv_len = blob . length ;
2007-07-16 15:08:00 +04:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSS-SPNEGO " , & cred , NULL , NULL , & scred ) ;
2002-09-25 19:19:00 +04:00
data_blob_free ( & blob ) ;
2004-01-08 11:19:18 +03:00
data_blob_free ( & session_key ) ;
2004-05-07 03:08:56 +04:00
if ( scred )
ber_bvfree ( scred ) ;
2002-09-25 19:19:00 +04:00
return ADS_ERROR ( rc ) ;
}
2007-07-25 14:34:16 +04:00
2007-07-31 13:31:47 +04:00
static ADS_STATUS ads_sasl_spnego_krb5_bind ( ADS_STRUCT * ads ,
struct ads_service_principal * p )
2007-07-25 14:34:16 +04:00
{
# ifdef HAVE_GSSAPI
/*
* we only use the gsskrb5 based implementation
* when sasl sign or seal is requested .
*
* This has the following reasons :
* - it ' s likely that the gssapi krb5 mech implementation
* doesn ' t support to negotiate plain connections
* - the ads_sasl_spnego_rawkrb5_bind is more robust
* against clock skew errors
*/
if ( ads - > ldap . wrap_type > ADS_SASLWRAP_TYPE_PLAIN ) {
2007-07-31 13:31:47 +04:00
return ads_sasl_spnego_gsskrb5_bind ( ads , p - > name ) ;
2007-07-25 14:34:16 +04:00
}
# endif
2007-07-31 13:31:47 +04:00
return ads_sasl_spnego_rawkrb5_bind ( ads , p - > string ) ;
2007-07-25 14:34:16 +04:00
}
2006-12-12 23:27:01 +03:00
# endif
2002-09-25 19:19:00 +04:00
/*
this performs a SASL / SPNEGO bind
*/
static ADS_STATUS ads_sasl_spnego_bind ( ADS_STRUCT * ads )
{
struct berval * scred = NULL ;
int rc , i ;
ADS_STATUS status ;
DATA_BLOB blob ;
2007-07-31 13:31:47 +04:00
char * given_principal = NULL ;
2002-09-25 19:19:00 +04:00
char * OIDs [ ASN1_MAX_OIDS ] ;
2005-03-22 18:12:50 +03:00
# ifdef HAVE_KRB5
2002-09-25 19:19:00 +04:00
BOOL got_kerberos_mechanism = False ;
2005-03-22 18:12:50 +03:00
# endif
2002-09-25 19:19:00 +04:00
2007-07-16 15:08:00 +04:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSS-SPNEGO " , NULL , NULL , NULL , & scred ) ;
2002-09-25 19:19:00 +04:00
if ( rc ! = LDAP_SASL_BIND_IN_PROGRESS ) {
status = ADS_ERROR ( rc ) ;
goto failed ;
}
blob = data_blob ( scred - > bv_val , scred - > bv_len ) ;
2004-01-08 11:19:18 +03:00
ber_bvfree ( scred ) ;
2002-09-25 19:19:00 +04:00
#if 0
file_save ( " sasl_spnego.dat " , blob . data , blob . length ) ;
2001-12-08 14:18:56 +03:00
# endif
2002-09-25 19:19:00 +04:00
/* the server sent us the first part of the SPNEGO exchange in the negprot
reply */
2007-07-31 13:31:47 +04:00
if ( ! spnego_parse_negTokenInit ( blob , OIDs , & given_principal ) ) {
2002-09-25 19:19:00 +04:00
data_blob_free ( & blob ) ;
status = ADS_ERROR ( LDAP_OPERATIONS_ERROR ) ;
goto failed ;
}
data_blob_free ( & blob ) ;
/* make sure the server understands kerberos */
for ( i = 0 ; OIDs [ i ] ; i + + ) {
2004-07-07 22:12:09 +04:00
DEBUG ( 3 , ( " ads_sasl_spnego_bind: got OID=%s \n " , OIDs [ i ] ) ) ;
2005-03-22 18:12:50 +03:00
# ifdef HAVE_KRB5
2002-09-25 19:19:00 +04:00
if ( strcmp ( OIDs [ i ] , OID_KERBEROS5_OLD ) = = 0 | |
strcmp ( OIDs [ i ] , OID_KERBEROS5 ) = = 0 ) {
got_kerberos_mechanism = True ;
}
2005-03-22 18:12:50 +03:00
# endif
2002-09-25 19:19:00 +04:00
free ( OIDs [ i ] ) ;
}
2007-07-31 13:31:47 +04:00
DEBUG ( 3 , ( " ads_sasl_spnego_bind: got server principal name = %s \n " , given_principal ) ) ;
2001-12-08 14:18:56 +03:00
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 ) & &
2007-02-10 23:29:09 +03:00
got_kerberos_mechanism )
{
2007-07-31 13:31:47 +04:00
struct ads_service_principal p ;
status = ads_generate_service_principal ( ads , given_principal , & p ) ;
SAFE_FREE ( given_principal ) ;
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
2007-02-10 23:29:09 +03:00
}
2007-07-31 13:31:47 +04:00
status = ads_sasl_spnego_krb5_bind ( ads , & p ) ;
2004-05-07 03:08:56 +04:00
if ( ADS_ERR_OK ( status ) ) {
2007-07-31 13:31:47 +04:00
ads_free_service_principal ( & p ) ;
2002-11-10 06:07:19 +03:00
return status ;
2004-05-07 03:08:56 +04:00
}
2004-01-08 11:19:18 +03:00
2007-02-08 20:02:39 +03:00
DEBUG ( 10 , ( " ads_sasl_spnego_krb5_bind failed with: %s, "
" calling kinit \n " , ads_errstr ( status ) ) ) ;
2004-01-08 11:19:18 +03:00
status = ADS_ERROR_KRB5 ( ads_kinit_password ( ads ) ) ;
if ( ADS_ERR_OK ( status ) ) {
2007-07-31 13:31:47 +04:00
status = ads_sasl_spnego_krb5_bind ( ads , & p ) ;
2003-04-24 18:07:13 +04:00
}
2004-01-08 11:19:18 +03:00
2007-07-31 13:31:47 +04:00
ads_free_service_principal ( & p ) ;
2003-06-10 07:47:42 +04:00
/* only fallback to NTLMSSP if allowed */
if ( ADS_ERR_OK ( status ) | |
! ( ads - > auth . flags & ADS_AUTH_ALLOW_NTLMSSP ) ) {
2003-04-24 18:07:13 +04:00
return status ;
2003-06-10 07:47:42 +04:00
}
2007-07-31 13:31:47 +04:00
} else
2002-10-01 22:26:00 +04:00
# endif
2007-07-31 13:31:47 +04:00
{
SAFE_FREE ( given_principal ) ;
}
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
to sync clocks , and we don ' t rely on special versions of the krb5
library for HMAC_MD4 encryption */
return ads_sasl_spnego_ntlmssp_bind ( ads ) ;
failed :
return status ;
}
# ifdef HAVE_GSSAPI
2001-12-08 14:18:56 +03: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 19:19:00 +04:00
see RFC2078 and RFC2222 for details
2001-12-08 14:18:56 +03:00
*/
2007-07-31 13:49:14 +04:00
static ADS_STATUS ads_sasl_gssapi_do_bind ( ADS_STRUCT * ads , const gss_name_t serv_name )
2001-12-08 14:18:56 +03:00
{
2003-08-16 01:19:34 +04:00
uint32 minor_status ;
2007-04-04 18:50:39 +04:00
gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT ;
2001-12-08 14:18:56 +03:00
gss_OID mech_type = GSS_C_NULL_OID ;
gss_buffer_desc output_token , input_token ;
2007-07-18 12:19:13 +04:00
uint32 req_flags , ret_flags ;
int conf_state ;
2001-12-08 14:18:56 +03:00
struct berval cred ;
2004-05-07 03:08:56 +04:00
struct berval * scred = NULL ;
2001-12-08 14:18:56 +03:00
int i = 0 ;
2001-12-19 15:21:12 +03:00
int gss_rc , rc ;
2001-12-08 14:18:56 +03:00
uint8 * p ;
2006-08-29 04:53:28 +04:00
uint32 max_msg_size = 0 ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-12-08 14:18:56 +03:00
input_token . value = NULL ;
input_token . length = 0 ;
2007-07-18 12:19:13 +04:00
req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG ;
switch ( ads - > ldap . wrap_type ) {
case ADS_SASLWRAP_TYPE_SEAL :
req_flags | = GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG ;
break ;
case ADS_SASLWRAP_TYPE_SIGN :
req_flags | = GSS_C_INTEG_FLAG ;
break ;
case ADS_SASLWRAP_TYPE_PLAIN :
break ;
}
2001-12-08 14:18:56 +03:00
for ( i = 0 ; i < MAX_GSS_PASSES ; i + + ) {
gss_rc = gss_init_sec_context ( & minor_status ,
GSS_C_NO_CREDENTIAL ,
& context_handle ,
serv_name ,
mech_type ,
2007-07-18 12:19:13 +04:00
req_flags ,
2001-12-08 14:18:56 +03:00
0 ,
NULL ,
& input_token ,
NULL ,
& output_token ,
& ret_flags ,
NULL ) ;
2007-08-02 19:11:37 +04:00
if ( scred ) {
ber_bvfree ( scred ) ;
scred = NULL ;
2001-12-08 14:18:56 +03:00
}
2001-12-19 11:44:23 +03:00
if ( gss_rc & & gss_rc ! = GSS_S_CONTINUE_NEEDED ) {
2001-12-19 15:21:12 +03:00
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
2001-12-19 11:44:23 +03:00
}
2001-12-08 14:18:56 +03:00
2006-09-04 23:47:48 +04:00
cred . bv_val = ( char * ) output_token . value ;
2001-12-08 14:18:56 +03:00
cred . bv_len = output_token . length ;
2007-07-16 15:08:00 +04:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSSAPI " , & cred , NULL , NULL ,
2001-12-08 14:18:56 +03:00
& scred ) ;
2001-12-19 15:21:12 +03:00
if ( rc ! = LDAP_SASL_BIND_IN_PROGRESS ) {
status = ADS_ERROR ( rc ) ;
goto failed ;
}
2001-12-08 14:18:56 +03: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 15:21:12 +03:00
if ( gss_rc = = 0 ) break ;
2001-12-08 14:18:56 +03:00
}
gss_rc = gss_unwrap ( & minor_status , context_handle , & input_token , & output_token ,
2007-07-18 12:19:13 +04:00
& conf_state , NULL ) ;
2007-08-02 19:11:37 +04:00
if ( scred ) {
ber_bvfree ( scred ) ;
scred = NULL ;
}
2001-12-19 15:21:12 +03:00
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
2001-12-08 14:18:56 +03:00
p = ( uint8 * ) output_token . value ;
2006-02-04 01:19:41 +03:00
#if 0
2002-09-25 19:19:00 +04:00
file_save ( " sasl_gssapi.dat " , output_token . value , output_token . length ) ;
2006-02-04 01:19:41 +03:00
# endif
2006-08-29 04:53:28 +04:00
if ( p ) {
max_msg_size = ( p [ 1 ] < < 16 ) | ( p [ 2 ] < < 8 ) | p [ 3 ] ;
}
2001-12-08 14:18:56 +03:00
gss_release_buffer ( & minor_status , & output_token ) ;
2007-04-10 20:04:22 +04:00
output_token . length = 4 ;
output_token . value = SMB_MALLOC ( output_token . length ) ;
2006-09-04 23:47:48 +04:00
p = ( uint8 * ) output_token . value ;
2001-12-08 14:18:56 +03:00
2007-07-18 12:19:13 +04:00
* p + + = ads - > ldap . wrap_type ;
2001-12-08 14:18:56 +03:00
/* choose the same size as the server gave us */
* p + + = max_msg_size > > 16 ;
* p + + = max_msg_size > > 8 ;
* p + + = max_msg_size ;
2007-04-10 20:04:22 +04: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 14:18:56 +03:00
2001-12-19 15:21:12 +03:00
gss_rc = gss_wrap ( & minor_status , context_handle , 0 , GSS_C_QOP_DEFAULT ,
2007-07-18 12:19:13 +04:00
& output_token , & conf_state ,
2001-12-08 14:18:56 +03:00
& input_token ) ;
2001-12-19 15:21:12 +03:00
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
2001-12-08 14:18:56 +03:00
free ( output_token . value ) ;
2006-09-04 23:47:48 +04:00
cred . bv_val = ( char * ) input_token . value ;
2001-12-08 14:18:56 +03:00
cred . bv_len = input_token . length ;
2007-07-16 15:08:00 +04:00
rc = ldap_sasl_bind_s ( ads - > ldap . ld , NULL , " GSSAPI " , & cred , NULL , NULL ,
2001-12-08 14:18:56 +03:00
& scred ) ;
gss_release_buffer ( & minor_status , & input_token ) ;
2007-07-25 11:23:20 +04:00
status = ADS_ERROR ( rc ) ;
if ( ! ADS_ERR_OK ( status ) ) {
goto failed ;
}
2001-12-08 14:18:56 +03:00
2007-07-18 12:19:13 +04: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 ,
max_msg_size , & ads - > ldap . out . max ) ;
if ( gss_rc ) {
status = ADS_ERROR_GSS ( gss_rc , minor_status ) ;
goto failed ;
}
ads - > ldap . out . min = 4 ;
ads - > ldap . out . sig_size = max_msg_size - ads - > ldap . out . max ;
ads - > ldap . in . min = 4 ;
ads - > ldap . in . max = max_msg_size ;
2007-07-31 16:27:25 +04:00
status = ads_setup_sasl_wrapping ( ads , & ads_sasl_gssapi_ops , context_handle ) ;
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 ) ) ) ;
goto failed ;
}
2007-07-18 12:19:13 +04:00
/* make sure we don't free context_handle */
context_handle = GSS_C_NO_CONTEXT ;
}
2001-12-08 14:18:56 +03:00
failed :
2007-03-16 01:11:13 +03:00
2007-04-04 18:50:39 +04:00
if ( context_handle ! = GSS_C_NO_CONTEXT )
2007-04-04 21:38:12 +04:00
gss_delete_sec_context ( & minor_status , & context_handle , GSS_C_NO_BUFFER ) ;
2007-03-16 01:11:13 +03:00
2004-05-07 03:08:56 +04:00
if ( scred )
ber_bvfree ( scred ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-12-08 14:18:56 +03:00
}
2007-07-31 13:49:14 +04:00
static ADS_STATUS ads_sasl_gssapi_bind ( ADS_STRUCT * ads )
{
ADS_STATUS status ;
struct ads_service_principal p ;
status = ads_generate_service_principal ( ads , NULL , & p ) ;
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
status = ads_sasl_gssapi_do_bind ( ads , p . name ) ;
if ( ADS_ERR_OK ( status ) ) {
ads_free_service_principal ( & p ) ;
return status ;
}
DEBUG ( 10 , ( " ads_sasl_gssapi_do_bind failed with: %s, "
" calling kinit \n " , ads_errstr ( status ) ) ) ;
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 ;
}
2006-01-26 00:25:25 +03:00
# endif /* HAVE_GGSAPI */
2002-09-25 19:19:00 +04: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 } ,
# ifdef HAVE_GSSAPI
{ " GSSAPI " , ads_sasl_gssapi_bind } , /* doesn't work with .NET RC1. No idea why */
# endif
{ NULL , NULL }
} ;
2001-12-08 14:18:56 +03:00
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
const char * attrs [ ] = { " supportedSASLMechanisms " , NULL } ;
char * * values ;
ADS_STATUS status ;
int i , j ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2002-09-25 19:19:00 +04: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 15:08:00 +04:00
values = ldap_get_values ( ads - > ldap . ld , res , " supportedSASLMechanisms " ) ;
2002-09-25 19:19:00 +04:00
2007-07-18 11:45:16 +04: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 19:19:00 +04: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 ] ) ) ;
status = sasl_mechanisms [ i ] . fn ( ads ) ;
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 14:18:56 +03:00
}
2006-01-26 00:25:25 +03:00
# endif /* HAVE_LDAP */
2001-12-08 14:18:56 +03:00