2004-02-10 10:22:12 +00:00
/*
Unix SMB / CIFS implementation .
dcerpc schannel operations
Copyright ( C ) Andrew Tridgell 2004
r6028: A MAJOR update to intergrate the new credentails system fully with
GENSEC, and to pull SCHANNEL into GENSEC, by making it less 'special'.
GENSEC now no longer has it's own handling of 'set username' etc,
instead it uses cli_credentials calls.
In order to link the credentails code right though Samba, a lot of
interfaces have changed to remove 'username, domain, password'
arguments, and these have been replaced with a single 'struct
cli_credentials'.
In the session setup code, a new parameter 'workgroup' contains the
client/server current workgroup, which seems unrelated to the
authentication exchange (it was being filled in from the auth info).
This allows in particular kerberos to only call back for passwords
when it actually needs to perform the kinit.
The kerberos code has been modified not to use the SPNEGO provided
'principal name' (in the mechListMIC), but to instead use the name the
host was connected to as. This better matches Microsoft behaviour,
is more secure and allows better use of standard kerberos functions.
To achieve this, I made changes to our socket code so that the
hostname (before name resolution) is now recorded on the socket.
In schannel, most of the code from librpc/rpc/dcerpc_schannel.c is now
in libcli/auth/schannel.c, and it looks much more like a standard
GENSEC module. The actual sign/seal code moved to
libcli/auth/schannel_sign.c in a previous commit.
The schannel credentails structure is now merged with the rest of the
credentails, as many of the values (username, workstation, domain)
where already present there. This makes handling this in a generic
manner much easier, as there is no longer a custom entry-point.
The auth_domain module continues to be developed, but is now just as
functional as auth_winbind. The changes here are consequential to the
schannel changes.
The only removed function at this point is the RPC-LOGIN test
(simulating the load of a WinXP login), which needs much more work to
clean it up (it contains copies of too much code from all over the
torture suite, and I havn't been able to penetrate its 'structure').
Andrew Bartlett
(This used to be commit 2301a4b38a21aa60917973451687063d83d18d66)
2005-03-24 04:14:06 +00:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2004 - 2005
2006-03-10 21:40:47 +00:00
Copyright ( C ) Rafal Szczesniak 2006
r6028: A MAJOR update to intergrate the new credentails system fully with
GENSEC, and to pull SCHANNEL into GENSEC, by making it less 'special'.
GENSEC now no longer has it's own handling of 'set username' etc,
instead it uses cli_credentials calls.
In order to link the credentails code right though Samba, a lot of
interfaces have changed to remove 'username, domain, password'
arguments, and these have been replaced with a single 'struct
cli_credentials'.
In the session setup code, a new parameter 'workgroup' contains the
client/server current workgroup, which seems unrelated to the
authentication exchange (it was being filled in from the auth info).
This allows in particular kerberos to only call back for passwords
when it actually needs to perform the kinit.
The kerberos code has been modified not to use the SPNEGO provided
'principal name' (in the mechListMIC), but to instead use the name the
host was connected to as. This better matches Microsoft behaviour,
is more secure and allows better use of standard kerberos functions.
To achieve this, I made changes to our socket code so that the
hostname (before name resolution) is now recorded on the socket.
In schannel, most of the code from librpc/rpc/dcerpc_schannel.c is now
in libcli/auth/schannel.c, and it looks much more like a standard
GENSEC module. The actual sign/seal code moved to
libcli/auth/schannel_sign.c in a previous commit.
The schannel credentails structure is now merged with the rest of the
credentails, as many of the values (username, workstation, domain)
where already present there. This makes handling this in a generic
manner much easier, as there is no longer a custom entry-point.
The auth_domain module continues to be developed, but is now just as
functional as auth_winbind. The changes here are consequential to the
schannel changes.
The only removed function at this point is the RPC-LOGIN test
(simulating the load of a WinXP login), which needs much more work to
clean it up (it contains copies of too much code from all over the
torture suite, and I havn't been able to penetrate its 'structure').
Andrew Bartlett
(This used to be commit 2301a4b38a21aa60917973451687063d83d18d66)
2005-03-24 04:14:06 +00:00
2004-02-10 10:22:12 +00: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-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2004-02-10 10:22:12 +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 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-02-10 10:22:12 +00:00
*/
# include "includes.h"
2010-03-10 10:17:25 +01:00
# include <tevent.h>
2004-11-02 02:57:18 +00:00
# include "auth/auth.h"
2006-03-09 23:21:49 +00:00
# include "libcli/composite/composite.h"
2006-03-14 15:03:25 +00:00
# include "libcli/auth/libcli_auth.h"
2006-03-16 00:23:11 +00:00
# include "librpc/gen_ndr/ndr_netlogon.h"
2006-03-14 23:35:30 +00:00
# include "librpc/gen_ndr/ndr_netlogon_c.h"
2006-11-07 00:48:36 +00:00
# include "auth/credentials/credentials.h"
2008-04-02 04:53:27 +02:00
# include "librpc/rpc/dcerpc_proto.h"
2008-11-02 02:05:48 +01:00
# include "param/param.h"
2006-03-09 23:21:49 +00:00
struct schannel_key_state {
struct dcerpc_pipe * pipe ;
struct dcerpc_pipe * pipe2 ;
struct dcerpc_binding * binding ;
2011-12-12 19:28:49 +01:00
bool dcerpc_schannel_auto ;
2006-03-09 23:21:49 +00:00
struct cli_credentials * credentials ;
2009-04-06 22:54:44 +10:00
struct netlogon_creds_CredentialState * creds ;
2011-12-12 19:28:49 +01:00
uint32_t local_negotiate_flags ;
uint32_t remote_negotiate_flags ;
2006-03-09 23:21:49 +00:00
struct netr_Credential credentials1 ;
struct netr_Credential credentials2 ;
struct netr_Credential credentials3 ;
2004-02-10 10:22:12 +00:00
struct netr_ServerReqChallenge r ;
struct netr_ServerAuthenticate2 a ;
2005-06-17 13:12:13 +00:00
const struct samr_Password * mach_pwd ;
2006-03-09 23:21:49 +00:00
} ;
static void continue_secondary_connection ( struct composite_context * ctx ) ;
static void continue_bind_auth_none ( struct composite_context * ctx ) ;
2010-03-10 10:17:25 +01:00
static void continue_srv_challenge ( struct tevent_req * subreq ) ;
static void continue_srv_auth2 ( struct tevent_req * subreq ) ;
2012-01-02 18:22:25 +01:00
static void continue_get_capabilities ( struct tevent_req * subreq ) ;
2006-03-09 23:21:49 +00:00
2006-03-10 21:40:47 +00:00
/*
Stage 2 of schannel_key : Receive endpoint mapping and request secondary
rpc connection
*/
2006-03-09 23:21:49 +00:00
static void continue_epm_map_binding ( struct composite_context * ctx )
{
struct composite_context * c ;
struct schannel_key_state * s ;
struct composite_context * sec_conn_req ;
c = talloc_get_type ( ctx - > async . private_data , struct composite_context ) ;
s = talloc_get_type ( c - > private_data , struct schannel_key_state ) ;
2006-03-10 21:40:47 +00:00
/* receive endpoint mapping */
2006-03-09 23:21:49 +00:00
c - > status = dcerpc_epm_map_binding_recv ( ctx ) ;
2006-07-30 17:34:37 +00:00
if ( ! NT_STATUS_IS_OK ( c - > status ) ) {
2006-03-09 23:21:49 +00:00
DEBUG ( 0 , ( " Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s \n " ,
2007-08-19 22:09:21 +00:00
NDR_NETLOGON_UUID , nt_errstr ( c - > status ) ) ) ;
2006-07-30 17:34:37 +00:00
composite_error ( c , c - > status ) ;
2006-03-09 23:21:49 +00:00
return ;
r6028: A MAJOR update to intergrate the new credentails system fully with
GENSEC, and to pull SCHANNEL into GENSEC, by making it less 'special'.
GENSEC now no longer has it's own handling of 'set username' etc,
instead it uses cli_credentials calls.
In order to link the credentails code right though Samba, a lot of
interfaces have changed to remove 'username, domain, password'
arguments, and these have been replaced with a single 'struct
cli_credentials'.
In the session setup code, a new parameter 'workgroup' contains the
client/server current workgroup, which seems unrelated to the
authentication exchange (it was being filled in from the auth info).
This allows in particular kerberos to only call back for passwords
when it actually needs to perform the kinit.
The kerberos code has been modified not to use the SPNEGO provided
'principal name' (in the mechListMIC), but to instead use the name the
host was connected to as. This better matches Microsoft behaviour,
is more secure and allows better use of standard kerberos functions.
To achieve this, I made changes to our socket code so that the
hostname (before name resolution) is now recorded on the socket.
In schannel, most of the code from librpc/rpc/dcerpc_schannel.c is now
in libcli/auth/schannel.c, and it looks much more like a standard
GENSEC module. The actual sign/seal code moved to
libcli/auth/schannel_sign.c in a previous commit.
The schannel credentails structure is now merged with the rest of the
credentails, as many of the values (username, workstation, domain)
where already present there. This makes handling this in a generic
manner much easier, as there is no longer a custom entry-point.
The auth_domain module continues to be developed, but is now just as
functional as auth_winbind. The changes here are consequential to the
schannel changes.
The only removed function at this point is the RPC-LOGIN test
(simulating the load of a WinXP login), which needs much more work to
clean it up (it contains copies of too much code from all over the
torture suite, and I havn't been able to penetrate its 'structure').
Andrew Bartlett
(This used to be commit 2301a4b38a21aa60917973451687063d83d18d66)
2005-03-24 04:14:06 +00:00
}
2004-06-06 07:58:16 +00:00
2006-03-10 21:40:47 +00:00
/* send a request for secondary rpc connection */
2006-03-10 10:54:37 +00:00
sec_conn_req = dcerpc_secondary_connection_send ( s - > pipe ,
2006-03-09 23:21:49 +00:00
s - > binding ) ;
if ( composite_nomem ( sec_conn_req , c ) ) return ;
composite_continue ( c , sec_conn_req , continue_secondary_connection , c ) ;
}
2006-03-10 21:40:47 +00:00
/*
Stage 3 of schannel_key : Receive secondary rpc connection and perform
non - authenticated bind request
*/
2006-03-09 23:21:49 +00:00
static void continue_secondary_connection ( struct composite_context * ctx )
{
struct composite_context * c ;
struct schannel_key_state * s ;
struct composite_context * auth_none_req ;
c = talloc_get_type ( ctx - > async . private_data , struct composite_context ) ;
s = talloc_get_type ( c - > private_data , struct schannel_key_state ) ;
2006-03-10 21:40:47 +00:00
/* receive secondary rpc connection */
2006-03-10 10:54:37 +00:00
c - > status = dcerpc_secondary_connection_recv ( ctx , & s - > pipe2 ) ;
2006-03-09 23:21:49 +00:00
if ( ! composite_is_ok ( c ) ) return ;
2006-07-30 17:34:37 +00:00
talloc_steal ( s , s - > pipe2 ) ;
2006-03-10 21:40:47 +00:00
/* initiate a non-authenticated bind */
2007-08-19 21:23:03 +00:00
auth_none_req = dcerpc_bind_auth_none_send ( c , s - > pipe2 , & ndr_table_netlogon ) ;
2006-03-09 23:21:49 +00:00
if ( composite_nomem ( auth_none_req , c ) ) return ;
composite_continue ( c , auth_none_req , continue_bind_auth_none , c ) ;
}
2006-03-10 21:40:47 +00:00
/*
Stage 4 of schannel_key : Receive non - authenticated bind and get
a netlogon challenge
*/
2006-03-09 23:21:49 +00:00
static void continue_bind_auth_none ( struct composite_context * ctx )
{
struct composite_context * c ;
struct schannel_key_state * s ;
2010-03-10 10:17:25 +01:00
struct tevent_req * subreq ;
2006-03-09 23:21:49 +00:00
c = talloc_get_type ( ctx - > async . private_data , struct composite_context ) ;
s = talloc_get_type ( c - > private_data , struct schannel_key_state ) ;
2006-03-10 21:40:47 +00:00
/* receive result of non-authenticated bind request */
2006-03-09 23:21:49 +00:00
c - > status = dcerpc_bind_auth_none_recv ( ctx ) ;
2006-07-30 17:34:37 +00:00
if ( ! composite_is_ok ( c ) ) return ;
2006-03-10 21:40:47 +00:00
/* prepare a challenge request */
2006-03-09 23:21:49 +00:00
s - > r . in . server_name = talloc_asprintf ( c , " \\ \\ %s " , dcerpc_server_name ( s - > pipe ) ) ;
if ( composite_nomem ( s - > r . in . server_name , c ) ) return ;
s - > r . in . computer_name = cli_credentials_get_workstation ( s - > credentials ) ;
s - > r . in . credentials = & s - > credentials1 ;
2008-10-29 01:23:49 +01:00
s - > r . out . return_credentials = & s - > credentials2 ;
2006-03-10 21:40:47 +00:00
2006-03-09 23:21:49 +00:00
generate_random_buffer ( s - > credentials1 . data , sizeof ( s - > credentials1 . data ) ) ;
2004-02-10 10:22:12 +00:00
/*
2006-03-10 21:40:47 +00:00
request a netlogon challenge - a rpc request over opened secondary pipe
2004-02-10 10:22:12 +00:00
*/
2010-03-10 10:17:25 +01:00
subreq = dcerpc_netr_ServerReqChallenge_r_send ( s , c - > event_ctx ,
s - > pipe2 - > binding_handle ,
& s - > r ) ;
if ( composite_nomem ( subreq , c ) ) return ;
r5902: A rather large change...
I wanted to add a simple 'workstation' argument to the DCERPC
authenticated binding calls, but this patch kind of grew from there.
With SCHANNEL, the 'workstation' name (the netbios name of the client)
matters, as this is what ties the session between the NETLOGON ops and
the SCHANNEL bind. This changes a lot of files, and these will again
be changed when jelmer does the credentials work.
I also correct some schannel IDL to distinguish between workstation
names and account names. The distinction matters for domain trust
accounts.
Issues in handling this (issues with lifetime of talloc pointers)
caused me to change the 'creds_CredentialsState' and 'struct
dcerpc_binding' pointers to always be talloc()ed pointers.
In the schannel DB, we now store both the domain and computername, and
query on both. This should ensure we fault correctly when the domain
is specified incorrectly in the SCHANNEL bind.
In the RPC-SCHANNEL test, I finally fixed a bug that vl pointed out,
where the comment claimed we re-used a connection, but in fact we made
a new connection.
This was achived by breaking apart some of the
dcerpc_secondary_connection() logic.
The addition of workstation handling was also propogated to NTLMSSP
and GENSEC, for completeness.
The RPC-SAMSYNC test has been cleaned up a little, using a loop over
usernames/passwords rather than manually expanded tests. This will be
expanded further (the code in #if 0 in this patch) to use a newly
created user account for testing.
In making this test pass test_rpc.sh, I found a bug in the RPC-ECHO
server, caused by the removal of [ref] and the assoicated pointer from
the IDL. This has been re-added, until the underlying pidl issues are
solved.
(This used to be commit 824289dcc20908ddec957a4a892a103eec2da9b9)
2005-03-19 08:34:43 +00:00
2010-03-10 10:17:25 +01:00
tevent_req_set_callback ( subreq , continue_srv_challenge , c ) ;
2006-03-09 23:21:49 +00:00
}
2006-03-10 21:40:47 +00:00
/*
Stage 5 of schannel_key : Receive a challenge and perform authentication
on the netlogon pipe
*/
2010-03-10 10:17:25 +01:00
static void continue_srv_challenge ( struct tevent_req * subreq )
2006-03-09 23:21:49 +00:00
{
struct composite_context * c ;
struct schannel_key_state * s ;
r5902: A rather large change...
I wanted to add a simple 'workstation' argument to the DCERPC
authenticated binding calls, but this patch kind of grew from there.
With SCHANNEL, the 'workstation' name (the netbios name of the client)
matters, as this is what ties the session between the NETLOGON ops and
the SCHANNEL bind. This changes a lot of files, and these will again
be changed when jelmer does the credentials work.
I also correct some schannel IDL to distinguish between workstation
names and account names. The distinction matters for domain trust
accounts.
Issues in handling this (issues with lifetime of talloc pointers)
caused me to change the 'creds_CredentialsState' and 'struct
dcerpc_binding' pointers to always be talloc()ed pointers.
In the schannel DB, we now store both the domain and computername, and
query on both. This should ensure we fault correctly when the domain
is specified incorrectly in the SCHANNEL bind.
In the RPC-SCHANNEL test, I finally fixed a bug that vl pointed out,
where the comment claimed we re-used a connection, but in fact we made
a new connection.
This was achived by breaking apart some of the
dcerpc_secondary_connection() logic.
The addition of workstation handling was also propogated to NTLMSSP
and GENSEC, for completeness.
The RPC-SAMSYNC test has been cleaned up a little, using a loop over
usernames/passwords rather than manually expanded tests. This will be
expanded further (the code in #if 0 in this patch) to use a newly
created user account for testing.
In making this test pass test_rpc.sh, I found a bug in the RPC-ECHO
server, caused by the removal of [ref] and the assoicated pointer from
the IDL. This has been re-added, until the underlying pidl issues are
solved.
(This used to be commit 824289dcc20908ddec957a4a892a103eec2da9b9)
2005-03-19 08:34:43 +00:00
2010-03-10 10:17:25 +01:00
c = tevent_req_callback_data ( subreq , struct composite_context ) ;
2006-03-09 23:21:49 +00:00
s = talloc_get_type ( c - > private_data , struct schannel_key_state ) ;
2006-03-10 21:40:47 +00:00
/* receive rpc request result - netlogon challenge */
2010-03-10 10:17:25 +01:00
c - > status = dcerpc_netr_ServerReqChallenge_r_recv ( subreq , s ) ;
TALLOC_FREE ( subreq ) ;
2006-03-09 23:21:49 +00:00
if ( ! composite_is_ok ( c ) ) return ;
2004-02-10 10:22:12 +00:00
2006-03-10 21:40:47 +00:00
/* prepare credentials for auth2 request */
2006-03-09 23:21:49 +00:00
s - > mach_pwd = cli_credentials_get_nt_hash ( s - > credentials , c ) ;
2006-03-10 21:40:47 +00:00
/* auth2 request arguments */
2006-03-09 23:21:49 +00:00
s - > a . in . server_name = s - > r . in . server_name ;
s - > a . in . account_name = cli_credentials_get_username ( s - > credentials ) ;
s - > a . in . secure_channel_type =
cli_credentials_get_secure_channel_type ( s - > credentials ) ;
s - > a . in . computer_name = cli_credentials_get_workstation ( s - > credentials ) ;
2011-12-12 19:28:49 +01:00
s - > a . in . negotiate_flags = & s - > local_negotiate_flags ;
2006-03-09 23:21:49 +00:00
s - > a . in . credentials = & s - > credentials3 ;
2011-12-12 19:28:49 +01:00
s - > a . out . negotiate_flags = & s - > remote_negotiate_flags ;
2008-10-29 01:14:08 +01:00
s - > a . out . return_credentials = & s - > credentials3 ;
2006-03-09 23:21:49 +00:00
2009-04-06 22:54:44 +10:00
s - > creds = netlogon_creds_client_init ( s ,
s - > a . in . account_name ,
s - > a . in . computer_name ,
2012-12-19 13:53:23 +01:00
s - > a . in . secure_channel_type ,
2009-04-06 22:54:44 +10:00
& s - > credentials1 , & s - > credentials2 ,
2011-12-12 19:28:49 +01:00
s - > mach_pwd , & s - > credentials3 ,
s - > local_negotiate_flags ) ;
2009-04-06 22:54:44 +10:00
if ( composite_nomem ( s - > creds , c ) ) {
return ;
}
2006-03-10 21:40:47 +00:00
/*
authenticate on the netlogon pipe - a rpc request over secondary pipe
*/
2010-03-10 10:17:25 +01:00
subreq = dcerpc_netr_ServerAuthenticate2_r_send ( s , c - > event_ctx ,
s - > pipe2 - > binding_handle ,
& s - > a ) ;
if ( composite_nomem ( subreq , c ) ) return ;
2006-03-09 23:21:49 +00:00
2010-03-10 10:17:25 +01:00
tevent_req_set_callback ( subreq , continue_srv_auth2 , c ) ;
2006-03-09 23:21:49 +00:00
}
2004-02-10 10:22:12 +00:00
2006-03-10 21:40:47 +00:00
/*
Stage 6 of schannel_key : Receive authentication request result and verify
received credentials
*/
2010-03-10 10:17:25 +01:00
static void continue_srv_auth2 ( struct tevent_req * subreq )
2006-03-09 23:21:49 +00:00
{
struct composite_context * c ;
struct schannel_key_state * s ;
2010-03-10 10:17:25 +01:00
c = tevent_req_callback_data ( subreq , struct composite_context ) ;
2006-03-09 23:21:49 +00:00
s = talloc_get_type ( c - > private_data , struct schannel_key_state ) ;
2006-03-10 21:40:47 +00:00
/* receive rpc request result - auth2 credentials */
2010-03-10 10:17:25 +01:00
c - > status = dcerpc_netr_ServerAuthenticate2_r_recv ( subreq , s ) ;
TALLOC_FREE ( subreq ) ;
2006-03-09 23:21:49 +00:00
if ( ! composite_is_ok ( c ) ) return ;
2011-12-23 15:22:06 +01:00
if ( ! NT_STATUS_EQUAL ( s - > a . out . result , NT_STATUS_ACCESS_DENIED ) & &
! NT_STATUS_IS_OK ( s - > a . out . result ) ) {
composite_error ( c , s - > a . out . result ) ;
return ;
}
2011-12-12 19:28:49 +01:00
/*
* Strong keys could be unsupported ( NT4 ) or disables . So retry with the
* flags returned by the server . - asn
*/
2011-12-23 15:22:06 +01:00
if ( NT_STATUS_EQUAL ( s - > a . out . result , NT_STATUS_ACCESS_DENIED ) ) {
uint32_t lf = s - > local_negotiate_flags ;
const char * ln = NULL ;
uint32_t rf = s - > remote_negotiate_flags ;
const char * rn = NULL ;
if ( ! s - > dcerpc_schannel_auto ) {
composite_error ( c , s - > a . out . result ) ;
return ;
}
s - > dcerpc_schannel_auto = false ;
2011-12-23 15:20:26 +01:00
if ( lf & NETLOGON_NEG_SUPPORTS_AES ) {
ln = " aes " ;
if ( rf & NETLOGON_NEG_SUPPORTS_AES ) {
composite_error ( c , s - > a . out . result ) ;
return ;
}
} else if ( lf & NETLOGON_NEG_STRONG_KEYS ) {
2011-12-23 15:22:06 +01:00
ln = " strong " ;
if ( rf & NETLOGON_NEG_STRONG_KEYS ) {
composite_error ( c , s - > a . out . result ) ;
return ;
}
} else {
ln = " des " ;
}
2011-12-23 15:20:26 +01:00
if ( rf & NETLOGON_NEG_SUPPORTS_AES ) {
rn = " aes " ;
} else if ( rf & NETLOGON_NEG_STRONG_KEYS ) {
2011-12-23 15:22:06 +01:00
rn = " strong " ;
} else {
rn = " des " ;
}
DEBUG ( 3 , ( " Server doesn't support %s keys, downgrade to %s "
" and retry! local[0x%08X] remote[0x%08X] \n " ,
ln , rn , lf , rf ) ) ;
2011-12-12 19:28:49 +01:00
s - > local_negotiate_flags = s - > remote_negotiate_flags ;
generate_random_buffer ( s - > credentials1 . data ,
sizeof ( s - > credentials1 . data ) ) ;
subreq = dcerpc_netr_ServerReqChallenge_r_send ( s ,
c - > event_ctx ,
s - > pipe2 - > binding_handle ,
& s - > r ) ;
if ( composite_nomem ( subreq , c ) ) return ;
tevent_req_set_callback ( subreq , continue_srv_challenge , c ) ;
return ;
}
2011-12-22 16:32:31 +01:00
s - > creds - > negotiate_flags = s - > remote_negotiate_flags ;
2006-03-10 21:40:47 +00:00
/* verify credentials */
2009-04-06 22:54:44 +10:00
if ( ! netlogon_creds_client_check ( s - > creds , s - > a . out . return_credentials ) ) {
2006-03-09 23:21:49 +00:00
composite_error ( c , NT_STATUS_UNSUCCESSFUL ) ;
return ;
2004-02-10 10:22:12 +00:00
}
2006-03-09 23:21:49 +00:00
composite_done ( c ) ;
}
/*
2006-03-10 21:40:47 +00:00
Initiate establishing a schannel key using netlogon challenge
on a secondary pipe
2006-03-09 23:21:49 +00:00
*/
2013-09-20 04:14:00 +02:00
static struct composite_context * dcerpc_schannel_key_send ( TALLOC_CTX * mem_ctx ,
2006-03-09 23:21:49 +00:00
struct dcerpc_pipe * p ,
2007-12-07 03:01:41 +01:00
struct cli_credentials * credentials ,
struct loadparm_context * lp_ctx )
2006-03-09 23:21:49 +00:00
{
struct composite_context * c ;
struct schannel_key_state * s ;
struct composite_context * epm_map_req ;
2010-09-13 11:36:43 +10:00
enum netr_SchannelType schannel_type = cli_credentials_get_secure_channel_type ( credentials ) ;
2014-09-21 09:20:26 +02:00
struct cli_credentials * epm_creds = NULL ;
2006-03-10 21:40:47 +00:00
/* composite context allocation and setup */
2006-07-30 18:36:17 +00:00
c = composite_create ( mem_ctx , p - > conn - > event_ctx ) ;
2006-03-09 23:21:49 +00:00
if ( c = = NULL ) return NULL ;
s = talloc_zero ( c , struct schannel_key_state ) ;
if ( composite_nomem ( s , c ) ) return c ;
c - > private_data = s ;
2006-03-10 21:40:47 +00:00
/* store parameters in the state structure */
2006-03-09 23:21:49 +00:00
s - > pipe = p ;
s - > credentials = credentials ;
2011-12-12 19:28:49 +01:00
s - > local_negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS ;
2006-03-09 23:21:49 +00:00
2006-03-10 21:40:47 +00:00
/* allocate credentials */
2011-12-12 19:28:49 +01:00
if ( s - > pipe - > conn - > flags & DCERPC_SCHANNEL_128 ) {
s - > local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS ;
}
2011-12-23 15:20:26 +01:00
if ( s - > pipe - > conn - > flags & DCERPC_SCHANNEL_AES ) {
s - > local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS ;
s - > local_negotiate_flags | = NETLOGON_NEG_SUPPORTS_AES ;
}
2011-12-12 19:28:49 +01:00
if ( s - > pipe - > conn - > flags & DCERPC_SCHANNEL_AUTO ) {
s - > local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS ;
2011-12-23 15:20:26 +01:00
s - > local_negotiate_flags | = NETLOGON_NEG_SUPPORTS_AES ;
2011-12-12 19:28:49 +01:00
s - > dcerpc_schannel_auto = true ;
2004-02-10 10:22:12 +00:00
}
2004-05-30 13:44:40 +00:00
2011-12-23 15:26:07 +01:00
/* type of authentication depends on schannel type */
if ( schannel_type = = SEC_CHAN_RODC ) {
s - > local_negotiate_flags | = NETLOGON_NEG_RODC_PASSTHROUGH ;
}
2014-09-21 09:20:26 +02:00
epm_creds = cli_credentials_init_anon ( s ) ;
if ( composite_nomem ( epm_creds , c ) ) return c ;
2006-03-10 21:40:47 +00:00
/* allocate binding structure */
2014-02-06 18:51:45 +01:00
s - > binding = dcerpc_binding_dup ( s , s - > pipe - > binding ) ;
2006-03-09 23:21:49 +00:00
if ( composite_nomem ( s - > binding , c ) ) return c ;
2006-03-10 21:40:47 +00:00
/* request the netlogon endpoint mapping */
2006-03-09 23:21:49 +00:00
epm_map_req = dcerpc_epm_map_binding_send ( c , s - > binding ,
2007-08-19 21:23:03 +00:00
& ndr_table_netlogon ,
2014-09-21 09:20:26 +02:00
epm_creds ,
2007-12-07 03:01:41 +01:00
s - > pipe - > conn - > event_ctx ,
lp_ctx ) ;
2006-03-09 23:21:49 +00:00
if ( composite_nomem ( epm_map_req , c ) ) return c ;
composite_continue ( c , epm_map_req , continue_epm_map_binding , c ) ;
return c ;
}
2006-03-10 21:40:47 +00:00
/*
Receive result of schannel key request
*/
2013-09-20 04:16:00 +02:00
static NTSTATUS dcerpc_schannel_key_recv ( struct composite_context * c ,
TALLOC_CTX * mem_ctx ,
struct netlogon_creds_CredentialState * * creds )
2006-03-09 23:21:49 +00:00
{
NTSTATUS status = composite_wait ( c ) ;
2013-09-20 04:16:00 +02:00
if ( NT_STATUS_IS_OK ( status ) ) {
struct schannel_key_state * s =
talloc_get_type_abort ( c - > private_data ,
struct schannel_key_state ) ;
* creds = talloc_move ( mem_ctx , & s - > creds ) ;
}
2006-03-09 23:21:49 +00:00
talloc_free ( c ) ;
return status ;
}
struct auth_schannel_state {
struct dcerpc_pipe * pipe ;
struct cli_credentials * credentials ;
2007-08-19 20:46:45 +00:00
const struct ndr_interface_table * table ;
2007-12-07 02:37:04 +01:00
struct loadparm_context * lp_ctx ;
2006-03-09 23:21:49 +00:00
uint8_t auth_level ;
2012-01-02 18:22:25 +01:00
struct netlogon_creds_CredentialState * creds_state ;
2013-07-16 10:07:30 +02:00
struct netlogon_creds_CredentialState save_creds_state ;
2012-01-02 18:22:25 +01:00
struct netr_Authenticator auth ;
struct netr_Authenticator return_auth ;
union netr_Capabilities capabilities ;
struct netr_LogonGetCapabilities c ;
2006-03-09 23:21:49 +00:00
} ;
static void continue_bind_auth ( struct composite_context * ctx ) ;
2006-03-10 21:40:47 +00:00
/*
Stage 2 of auth_schannel : Receive schannel key and intitiate an
authenticated bind using received credentials
*/
2006-03-09 23:21:49 +00:00
static void continue_schannel_key ( struct composite_context * ctx )
{
struct composite_context * auth_req ;
struct composite_context * c = talloc_get_type ( ctx - > async . private_data ,
struct composite_context ) ;
struct auth_schannel_state * s = talloc_get_type ( c - > private_data ,
struct auth_schannel_state ) ;
2010-09-13 07:44:06 +10:00
NTSTATUS status ;
2006-03-09 23:21:49 +00:00
2006-03-10 21:40:47 +00:00
/* receive schannel key */
2013-09-20 04:16:00 +02:00
status = c - > status = dcerpc_schannel_key_recv ( ctx , s , & s - > creds_state ) ;
2006-03-09 23:21:49 +00:00
if ( ! composite_is_ok ( c ) ) {
2010-09-13 07:44:06 +10:00
DEBUG ( 1 , ( " Failed to setup credentials: %s \n " , nt_errstr ( status ) ) ) ;
2006-03-09 23:21:49 +00:00
return ;
2004-02-10 10:22:12 +00:00
}
2006-03-10 21:40:47 +00:00
/* send bind auth request with received creds */
2013-09-20 04:16:00 +02:00
cli_credentials_set_netlogon_creds ( s - > credentials , s - > creds_state ) ;
2006-03-09 23:21:49 +00:00
auth_req = dcerpc_bind_auth_send ( c , s - > pipe , s - > table , s - > credentials ,
2010-07-16 14:32:42 +10:00
lpcfg_gensec_settings ( c , s - > lp_ctx ) ,
2006-03-09 23:21:49 +00:00
DCERPC_AUTH_TYPE_SCHANNEL , s - > auth_level ,
NULL ) ;
if ( composite_nomem ( auth_req , c ) ) return ;
composite_continue ( c , auth_req , continue_bind_auth , c ) ;
}
r6028: A MAJOR update to intergrate the new credentails system fully with
GENSEC, and to pull SCHANNEL into GENSEC, by making it less 'special'.
GENSEC now no longer has it's own handling of 'set username' etc,
instead it uses cli_credentials calls.
In order to link the credentails code right though Samba, a lot of
interfaces have changed to remove 'username, domain, password'
arguments, and these have been replaced with a single 'struct
cli_credentials'.
In the session setup code, a new parameter 'workgroup' contains the
client/server current workgroup, which seems unrelated to the
authentication exchange (it was being filled in from the auth info).
This allows in particular kerberos to only call back for passwords
when it actually needs to perform the kinit.
The kerberos code has been modified not to use the SPNEGO provided
'principal name' (in the mechListMIC), but to instead use the name the
host was connected to as. This better matches Microsoft behaviour,
is more secure and allows better use of standard kerberos functions.
To achieve this, I made changes to our socket code so that the
hostname (before name resolution) is now recorded on the socket.
In schannel, most of the code from librpc/rpc/dcerpc_schannel.c is now
in libcli/auth/schannel.c, and it looks much more like a standard
GENSEC module. The actual sign/seal code moved to
libcli/auth/schannel_sign.c in a previous commit.
The schannel credentails structure is now merged with the rest of the
credentails, as many of the values (username, workstation, domain)
where already present there. This makes handling this in a generic
manner much easier, as there is no longer a custom entry-point.
The auth_domain module continues to be developed, but is now just as
functional as auth_winbind. The changes here are consequential to the
schannel changes.
The only removed function at this point is the RPC-LOGIN test
(simulating the load of a WinXP login), which needs much more work to
clean it up (it contains copies of too much code from all over the
torture suite, and I havn't been able to penetrate its 'structure').
Andrew Bartlett
(This used to be commit 2301a4b38a21aa60917973451687063d83d18d66)
2005-03-24 04:14:06 +00:00
2004-02-10 10:22:12 +00:00
2006-03-10 21:40:47 +00:00
/*
Stage 3 of auth_schannel : Receivce result of authenticated bind
and say if we ' re done ok .
*/
2006-03-09 23:21:49 +00:00
static void continue_bind_auth ( struct composite_context * ctx )
{
struct composite_context * c = talloc_get_type ( ctx - > async . private_data ,
struct composite_context ) ;
2012-01-02 18:22:25 +01:00
struct auth_schannel_state * s = talloc_get_type ( c - > private_data ,
struct auth_schannel_state ) ;
struct tevent_req * subreq ;
2006-03-09 23:21:49 +00:00
c - > status = dcerpc_bind_auth_recv ( ctx ) ;
if ( ! composite_is_ok ( c ) ) return ;
2012-01-02 18:22:25 +01:00
/* if we have a AES encrypted connection, verify the capabilities */
if ( ndr_syntax_id_equal ( & s - > table - > syntax_id ,
& ndr_table_netlogon . syntax_id ) ) {
ZERO_STRUCT ( s - > return_auth ) ;
2013-07-16 10:07:30 +02:00
s - > save_creds_state = * s - > creds_state ;
netlogon_creds_client_authenticator ( & s - > save_creds_state , & s - > auth ) ;
2012-01-02 18:22:25 +01:00
s - > c . in . server_name = talloc_asprintf ( c ,
" \\ \\ %s " ,
dcerpc_server_name ( s - > pipe ) ) ;
if ( composite_nomem ( s - > c . in . server_name , c ) ) return ;
s - > c . in . computer_name = cli_credentials_get_workstation ( s - > credentials ) ;
s - > c . in . credential = & s - > auth ;
s - > c . in . return_authenticator = & s - > return_auth ;
s - > c . in . query_level = 1 ;
s - > c . out . capabilities = & s - > capabilities ;
s - > c . out . return_authenticator = & s - > return_auth ;
DEBUG ( 5 , ( " We established a AES connection, verifying logon "
" capabilities \n " ) ) ;
subreq = dcerpc_netr_LogonGetCapabilities_r_send ( s ,
c - > event_ctx ,
s - > pipe - > binding_handle ,
& s - > c ) ;
if ( composite_nomem ( subreq , c ) ) return ;
tevent_req_set_callback ( subreq , continue_get_capabilities , c ) ;
return ;
}
composite_done ( c ) ;
}
/*
Stage 4 of auth_schannel : Get the Logon Capablities and verify them .
*/
static void continue_get_capabilities ( struct tevent_req * subreq )
{
struct composite_context * c ;
struct auth_schannel_state * s ;
c = tevent_req_callback_data ( subreq , struct composite_context ) ;
s = talloc_get_type ( c - > private_data , struct auth_schannel_state ) ;
/* receive rpc request result */
c - > status = dcerpc_netr_LogonGetCapabilities_r_recv ( subreq , s ) ;
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_EQUAL ( c - > status , NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ) ) {
if ( s - > creds_state - > negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
composite_error ( c , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
} else {
/* This is probably NT */
composite_done ( c ) ;
return ;
}
} else if ( ! composite_is_ok ( c ) ) {
return ;
}
if ( NT_STATUS_EQUAL ( s - > c . out . result , NT_STATUS_NOT_IMPLEMENTED ) ) {
if ( s - > creds_state - > negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
/* This means AES isn't supported. */
composite_error ( c , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
/* This is probably an old Samba version */
composite_done ( c ) ;
return ;
}
/* verify credentials */
2013-07-16 10:07:30 +02:00
if ( ! netlogon_creds_client_check ( & s - > save_creds_state ,
2012-01-02 18:22:25 +01:00
& s - > c . out . return_authenticator - > cred ) ) {
composite_error ( c , NT_STATUS_UNSUCCESSFUL ) ;
return ;
}
2013-07-16 10:07:30 +02:00
* s - > creds_state = s - > save_creds_state ;
2013-09-20 04:16:00 +02:00
cli_credentials_set_netlogon_creds ( s - > credentials , s - > creds_state ) ;
2013-07-16 10:07:30 +02:00
2012-01-02 18:22:25 +01:00
if ( ! NT_STATUS_IS_OK ( s - > c . out . result ) ) {
composite_error ( c , s - > c . out . result ) ;
return ;
}
/* compare capabilities */
if ( s - > creds_state - > negotiate_flags ! = s - > capabilities . server_capabilities ) {
DEBUG ( 2 , ( " The client capabilities don't match the server "
" capabilities: local[0x%08X] remote[0x%08X] \n " ,
s - > creds_state - > negotiate_flags ,
s - > capabilities . server_capabilities ) ) ;
composite_error ( c , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
/* TODO: Add downgrade dectection. */
2006-03-09 23:21:49 +00:00
composite_done ( c ) ;
}
2006-03-10 21:40:47 +00:00
/*
Initiate schannel authentication request
*/
2006-03-09 23:21:49 +00:00
struct composite_context * dcerpc_bind_auth_schannel_send ( TALLOC_CTX * tmp_ctx ,
struct dcerpc_pipe * p ,
2007-08-19 20:46:45 +00:00
const struct ndr_interface_table * table ,
2006-03-09 23:21:49 +00:00
struct cli_credentials * credentials ,
2007-12-07 02:37:04 +01:00
struct loadparm_context * lp_ctx ,
2006-03-09 23:21:49 +00:00
uint8_t auth_level )
{
struct composite_context * c ;
struct auth_schannel_state * s ;
struct composite_context * schan_key_req ;
2004-02-10 10:22:12 +00:00
2006-03-10 21:40:47 +00:00
/* composite context allocation and setup */
2006-07-30 18:36:17 +00:00
c = composite_create ( tmp_ctx , p - > conn - > event_ctx ) ;
2006-03-09 23:21:49 +00:00
if ( c = = NULL ) return NULL ;
s = talloc_zero ( c , struct auth_schannel_state ) ;
if ( composite_nomem ( s , c ) ) return c ;
c - > private_data = s ;
2006-07-30 18:36:17 +00:00
2006-03-10 21:40:47 +00:00
/* store parameters in the state structure */
2006-03-09 23:21:49 +00:00
s - > pipe = p ;
s - > credentials = credentials ;
s - > table = table ;
s - > auth_level = auth_level ;
2007-12-07 02:37:04 +01:00
s - > lp_ctx = lp_ctx ;
2006-03-09 23:21:49 +00:00
2006-03-10 21:40:47 +00:00
/* start getting schannel key first */
2007-12-07 03:01:41 +01:00
schan_key_req = dcerpc_schannel_key_send ( c , p , credentials , lp_ctx ) ;
2006-03-09 23:21:49 +00:00
if ( composite_nomem ( schan_key_req , c ) ) return c ;
composite_continue ( c , schan_key_req , continue_schannel_key , c ) ;
return c ;
}
2006-03-10 21:40:47 +00:00
/*
Receive result of schannel authentication request
*/
2006-03-09 23:21:49 +00:00
NTSTATUS dcerpc_bind_auth_schannel_recv ( struct composite_context * c )
{
NTSTATUS status = composite_wait ( c ) ;
talloc_free ( c ) ;
return status ;
2004-02-21 04:46:49 +00:00
}
2006-03-09 23:21:49 +00:00
2006-03-10 21:40:47 +00:00
/*
Perform schannel authenticated bind - sync version
*/
2008-04-02 04:53:27 +02:00
_PUBLIC_ NTSTATUS dcerpc_bind_auth_schannel ( TALLOC_CTX * tmp_ctx ,
2005-03-22 08:00:45 +00:00
struct dcerpc_pipe * p ,
2007-08-19 20:46:45 +00:00
const struct ndr_interface_table * table ,
2006-01-12 09:33:49 +00:00
struct cli_credentials * credentials ,
2007-12-07 02:37:04 +01:00
struct loadparm_context * lp_ctx ,
2006-01-12 09:33:49 +00:00
uint8_t auth_level )
2004-11-10 16:50:15 +00:00
{
2006-03-09 23:21:49 +00:00
struct composite_context * c ;
2004-11-10 16:50:15 +00:00
2007-12-07 02:37:04 +01:00
c = dcerpc_bind_auth_schannel_send ( tmp_ctx , p , table , credentials , lp_ctx ,
2006-03-09 23:21:49 +00:00
auth_level ) ;
return dcerpc_bind_auth_schannel_recv ( c ) ;
2004-11-10 16:50:15 +00:00
}