2005-03-01 23:53:18 +00:00
/*
Unix SMB / CIFS implementation .
Test suite for libnet calls .
Copyright ( C ) Rafal Szczesniak 2005
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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "librpc/gen_ndr/ndr_samr.h"
2005-03-07 05:12:33 +00:00
# include "libnet/composite.h"
# define TEST_USERNAME "libnetuserinfotest"
2005-03-01 23:53:18 +00:00
static BOOL test_opendomain ( struct dcerpc_pipe * p , TALLOC_CTX * mem_ctx ,
2005-03-07 05:12:33 +00:00
struct policy_handle * handle , struct samr_String * domname ,
struct dom_sid2 * sid )
2005-03-01 23:53:18 +00:00
{
NTSTATUS status ;
struct policy_handle h , domain_handle ;
struct samr_Connect r1 ;
struct samr_LookupDomain r2 ;
struct samr_OpenDomain r3 ;
printf ( " connecting \n " ) ;
r1 . in . system_name = 0 ;
r1 . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
r1 . out . connect_handle = & h ;
status = dcerpc_samr_Connect ( p , mem_ctx , & r1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Connect failed - %s \n " , nt_errstr ( status ) ) ;
return False ;
}
r2 . in . connect_handle = & h ;
r2 . in . domain_name = domname ;
r6165: fixed up the userinfo composite code. Fixes include:
- talloc should always be done in the right context. For example, when creating
the userinfo_state structure, place it inside the composite
structure, not directly on the pipe. If this isn't done then
correct cleanup can't happen on errors (as cleanup destroys the top
level composite context only)
- define private structures like userinfo_state in the userinfo.c
code, not in the public header
- only keep the parameters we need in the state structure. For
example, the domain_handle is only needed in the first call, so we
don't need to keep it around in the state structure, but the level is
needed in later calls, so we need to keep it
- always initialise [out,ref] parameters in RPC calls. The [ref] part
means that the call assumes the pointer it has been given is
valid. If you don't initialise it then you will get a segv on
recv. This is why the code was dying.
- don't use internal strucrure elements like the pipe
pipe->conn->pending outside of the internal rpc implementation. That
is an internal list, trying to use it from external code will cause crashes.
- rpc calls assume that rpc call strucrures remain valid for the
duration of the call. This means you need to keep the structures
(such as "struct samr_Close") in the userinfo_state strucrure,
otherwise it will go out of scope during the async processing
- need to remember to change c->state to SMBCLI_REQUEST_DONE when the
request has finished in the close handler, otherwise it will loop
forever trying to close
Mimir, please look at the diff carefully for more detailed info on the fixes
(This used to be commit 01ea1e7762e214e87e74d6f28d6efeb6cdea9736)
2005-04-01 11:24:52 +00:00
printf ( " domain lookup on %s \n " , domname - > string ) ;
2005-03-04 00:24:21 +00:00
2005-03-01 23:53:18 +00:00
status = dcerpc_samr_LookupDomain ( p , mem_ctx , & r2 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " LookupDomain failed - %s \n " , nt_errstr ( status ) ) ;
return False ;
}
r3 . in . connect_handle = & h ;
r3 . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
r3 . in . sid = r2 . out . sid ;
r3 . out . domain_handle = & domain_handle ;
2005-03-04 00:24:21 +00:00
printf ( " opening domain \n " ) ;
2005-03-01 23:53:18 +00:00
status = dcerpc_samr_OpenDomain ( p , mem_ctx , & r3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " OpenDomain failed - %s \n " , nt_errstr ( status ) ) ;
return False ;
} else {
* handle = domain_handle ;
}
2005-03-05 18:34:18 +00:00
2005-03-07 05:12:33 +00:00
* sid = * r2 . out . sid ;
return True ;
}
static BOOL test_cleanup ( struct dcerpc_pipe * p , TALLOC_CTX * mem_ctx ,
2005-03-07 12:27:03 +00:00
struct policy_handle * domain_handle , const char * username )
2005-03-07 05:12:33 +00:00
{
NTSTATUS status ;
struct samr_LookupNames r1 ;
struct samr_OpenUser r2 ;
struct samr_DeleteUser r3 ;
struct samr_String names [ 2 ] ;
uint32_t rid ;
struct policy_handle user_handle ;
names [ 0 ] . string = username ;
r1 . in . domain_handle = domain_handle ;
r1 . in . num_names = 1 ;
r1 . in . names = names ;
r6165: fixed up the userinfo composite code. Fixes include:
- talloc should always be done in the right context. For example, when creating
the userinfo_state structure, place it inside the composite
structure, not directly on the pipe. If this isn't done then
correct cleanup can't happen on errors (as cleanup destroys the top
level composite context only)
- define private structures like userinfo_state in the userinfo.c
code, not in the public header
- only keep the parameters we need in the state structure. For
example, the domain_handle is only needed in the first call, so we
don't need to keep it around in the state structure, but the level is
needed in later calls, so we need to keep it
- always initialise [out,ref] parameters in RPC calls. The [ref] part
means that the call assumes the pointer it has been given is
valid. If you don't initialise it then you will get a segv on
recv. This is why the code was dying.
- don't use internal strucrure elements like the pipe
pipe->conn->pending outside of the internal rpc implementation. That
is an internal list, trying to use it from external code will cause crashes.
- rpc calls assume that rpc call strucrures remain valid for the
duration of the call. This means you need to keep the structures
(such as "struct samr_Close") in the userinfo_state strucrure,
otherwise it will go out of scope during the async processing
- need to remember to change c->state to SMBCLI_REQUEST_DONE when the
request has finished in the close handler, otherwise it will loop
forever trying to close
Mimir, please look at the diff carefully for more detailed info on the fixes
(This used to be commit 01ea1e7762e214e87e74d6f28d6efeb6cdea9736)
2005-04-01 11:24:52 +00:00
printf ( " user account lookup '%s' \n " , username ) ;
2005-03-07 05:12:33 +00:00
status = dcerpc_samr_LookupNames ( p , mem_ctx , & r1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " LookupNames failed - %s \n " , nt_errstr ( status ) ) ;
return False ;
}
rid = r1 . out . rids . ids [ 0 ] ;
r2 . in . domain_handle = domain_handle ;
r2 . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
r2 . in . rid = rid ;
r2 . out . user_handle = & user_handle ;
printf ( " opening user account \n " ) ;
status = dcerpc_samr_OpenUser ( p , mem_ctx , & r2 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " OpenUser failed - %s \n " , nt_errstr ( status ) ) ;
return False ;
}
r3 . in . user_handle = & user_handle ;
r3 . out . user_handle = & user_handle ;
printf ( " deleting user account \n " ) ;
status = dcerpc_samr_DeleteUser ( p , mem_ctx , & r3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " DeleteUser failed - %s \n " , nt_errstr ( status ) ) ;
return False ;
}
return True ;
}
static BOOL test_create ( struct dcerpc_pipe * p , TALLOC_CTX * mem_ctx ,
struct policy_handle * handle , const char * name , uint32_t * rid )
{
NTSTATUS status ;
struct samr_String username ;
struct samr_CreateUser r ;
struct policy_handle user_handle ;
username . string = name ;
r . in . domain_handle = handle ;
r . in . account_name = & username ;
r . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
r . out . user_handle = & user_handle ;
r . out . rid = rid ;
r6165: fixed up the userinfo composite code. Fixes include:
- talloc should always be done in the right context. For example, when creating
the userinfo_state structure, place it inside the composite
structure, not directly on the pipe. If this isn't done then
correct cleanup can't happen on errors (as cleanup destroys the top
level composite context only)
- define private structures like userinfo_state in the userinfo.c
code, not in the public header
- only keep the parameters we need in the state structure. For
example, the domain_handle is only needed in the first call, so we
don't need to keep it around in the state structure, but the level is
needed in later calls, so we need to keep it
- always initialise [out,ref] parameters in RPC calls. The [ref] part
means that the call assumes the pointer it has been given is
valid. If you don't initialise it then you will get a segv on
recv. This is why the code was dying.
- don't use internal strucrure elements like the pipe
pipe->conn->pending outside of the internal rpc implementation. That
is an internal list, trying to use it from external code will cause crashes.
- rpc calls assume that rpc call strucrures remain valid for the
duration of the call. This means you need to keep the structures
(such as "struct samr_Close") in the userinfo_state strucrure,
otherwise it will go out of scope during the async processing
- need to remember to change c->state to SMBCLI_REQUEST_DONE when the
request has finished in the close handler, otherwise it will loop
forever trying to close
Mimir, please look at the diff carefully for more detailed info on the fixes
(This used to be commit 01ea1e7762e214e87e74d6f28d6efeb6cdea9736)
2005-04-01 11:24:52 +00:00
printf ( " creating user account %s \n " , name ) ;
2005-03-07 05:12:33 +00:00
status = dcerpc_samr_CreateUser ( p , mem_ctx , & r ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " CreateUser failed - %s \n " , nt_errstr ( status ) ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_USER_EXISTS ) ) {
printf ( " User (%s) already exists - attempting to delete and recreate account again \n " , name ) ;
if ( ! test_cleanup ( p , mem_ctx , handle , TEST_USERNAME ) ) {
return False ;
}
printf ( " creating user account \n " ) ;
status = dcerpc_samr_CreateUser ( p , mem_ctx , & r ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " CreateUser failed - %s \n " , nt_errstr ( status ) ) ;
return False ;
}
return True ;
}
return False ;
}
return True ;
}
static BOOL test_userinfo ( struct dcerpc_pipe * p , TALLOC_CTX * mem_ctx ,
struct policy_handle * domain_handle ,
2005-03-07 12:27:03 +00:00
struct dom_sid2 * domain_sid , const char * user_name ,
2005-03-07 05:12:33 +00:00
uint32_t * rid )
{
NTSTATUS status ;
struct rpc_composite_userinfo user ;
struct dom_sid * user_sid ;
user_sid = dom_sid_add_rid ( mem_ctx , domain_sid , * rid ) ;
user . in . domain_handle = * domain_handle ;
user . in . sid = dom_sid_string ( mem_ctx , user_sid ) ;
user . in . level = 5 ; /* this should be extended */
printf ( " Testing sync rpc_composite_userinfo \n " ) ;
status = rpc_composite_userinfo ( p , mem_ctx , & user ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to call sync rpc_composite_userinfo - %s \n " , nt_errstr ( status ) ) ;
return False ;
}
2005-03-05 18:34:18 +00:00
return True ;
2005-03-01 23:53:18 +00:00
}
BOOL torture_userinfo ( void )
{
NTSTATUS status ;
2005-03-04 00:24:21 +00:00
const char * binding ;
2005-03-01 23:53:18 +00:00
struct dcerpc_pipe * p ;
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
struct dcerpc_binding * b ;
2005-03-01 23:53:18 +00:00
TALLOC_CTX * mem_ctx ;
BOOL ret = True ;
2005-03-07 12:27:03 +00:00
struct policy_handle h ;
2005-03-04 00:24:21 +00:00
struct samr_String name ;
2005-03-07 05:12:33 +00:00
struct dom_sid2 sid ;
uint32_t rid ;
2005-03-01 23:53:18 +00:00
mem_ctx = talloc_init ( " test_userinfo " ) ;
2005-03-04 00:24:21 +00:00
binding = lp_parm_string ( - 1 , " torture " , " binding " ) ;
2005-03-22 08:00:45 +00:00
status = torture_rpc_connection ( mem_ctx ,
& p ,
2005-03-01 23:53:18 +00:00
DCERPC_SAMR_NAME ,
DCERPC_SAMR_UUID ,
DCERPC_SAMR_VERSION ) ;
2005-04-22 00:32:37 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) return False ;
2005-03-01 23:53:18 +00:00
r6165: fixed up the userinfo composite code. Fixes include:
- talloc should always be done in the right context. For example, when creating
the userinfo_state structure, place it inside the composite
structure, not directly on the pipe. If this isn't done then
correct cleanup can't happen on errors (as cleanup destroys the top
level composite context only)
- define private structures like userinfo_state in the userinfo.c
code, not in the public header
- only keep the parameters we need in the state structure. For
example, the domain_handle is only needed in the first call, so we
don't need to keep it around in the state structure, but the level is
needed in later calls, so we need to keep it
- always initialise [out,ref] parameters in RPC calls. The [ref] part
means that the call assumes the pointer it has been given is
valid. If you don't initialise it then you will get a segv on
recv. This is why the code was dying.
- don't use internal strucrure elements like the pipe
pipe->conn->pending outside of the internal rpc implementation. That
is an internal list, trying to use it from external code will cause crashes.
- rpc calls assume that rpc call strucrures remain valid for the
duration of the call. This means you need to keep the structures
(such as "struct samr_Close") in the userinfo_state strucrure,
otherwise it will go out of scope during the async processing
- need to remember to change c->state to SMBCLI_REQUEST_DONE when the
request has finished in the close handler, otherwise it will loop
forever trying to close
Mimir, please look at the diff carefully for more detailed info on the fixes
(This used to be commit 01ea1e7762e214e87e74d6f28d6efeb6cdea9736)
2005-04-01 11:24:52 +00:00
name . string = lp_workgroup ( ) ;
2005-03-04 00:24:21 +00:00
2005-03-07 05:12:33 +00:00
if ( ! test_opendomain ( p , mem_ctx , & h , & name , & sid ) ) {
2005-03-01 23:53:18 +00:00
ret = False ;
2005-03-07 05:12:33 +00:00
goto done ;
2005-03-01 23:53:18 +00:00
}
2005-03-07 05:12:33 +00:00
if ( ! test_create ( p , mem_ctx , & h , TEST_USERNAME , & rid ) ) {
ret = False ;
goto done ;
}
if ( ! test_userinfo ( p , mem_ctx , & h , & sid , TEST_USERNAME , & rid ) ) {
ret = False ;
goto done ;
}
if ( ! test_cleanup ( p , mem_ctx , & h , TEST_USERNAME ) ) {
ret = False ;
goto done ;
}
2005-03-04 00:24:21 +00:00
done :
2005-03-01 23:53:18 +00:00
talloc_free ( mem_ctx ) ;
return ret ;
}