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"
2006-03-14 15:02:05 +00:00
# include "torture/rpc/rpc.h"
2005-12-28 15:38:36 +00:00
# include "libnet/libnet.h"
2006-04-02 12:02:01 +00:00
# include "libcli/security/security.h"
2006-03-14 23:35:30 +00:00
# include "librpc/gen_ndr/ndr_samr_c.h"
2005-03-07 05:12:33 +00:00
# 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-07-08 08:09:02 +00:00
struct policy_handle * handle , struct lsa_String * domname ,
2005-03-07 05:12:33 +00:00
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 ;
2005-07-08 08:09:02 +00:00
struct lsa_String names [ 2 ] ;
2005-03-07 05:12:33 +00:00
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 ;
2005-07-08 08:09:02 +00:00
struct lsa_String username ;
2005-03-07 05:12:33 +00:00
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 ;
2005-06-11 10:33:31 +00:00
struct libnet_rpc_userinfo user ;
2005-03-07 05:12:33 +00:00
struct dom_sid * user_sid ;
2005-05-06 19:36:49 +00:00
2005-03-07 05:12:33 +00:00
user_sid = dom_sid_add_rid ( mem_ctx , domain_sid , * rid ) ;
2005-05-06 19:36:49 +00:00
2005-03-07 05:12:33 +00:00
user . in . domain_handle = * domain_handle ;
user . in . sid = dom_sid_string ( mem_ctx , user_sid ) ;
user . in . level = 5 ; /* this should be extended */
2005-06-11 10:33:31 +00:00
printf ( " Testing sync libnet_rpc_userinfo \n " ) ;
status = libnet_rpc_userinfo ( p , mem_ctx , & user ) ;
2005-03-07 05:12:33 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-06-11 10:33:31 +00:00
printf ( " Failed to call sync libnet_rpc_userinfo - %s \n " , nt_errstr ( status ) ) ;
2005-03-07 05:12:33 +00:00
return False ;
}
2005-03-05 18:34:18 +00:00
return True ;
2005-03-01 23:53:18 +00:00
}
2005-05-10 18:17:40 +00:00
static void msg_handler ( struct monitor_msg * m )
2005-05-06 19:36:49 +00:00
{
2005-07-25 22:57:14 +00:00
struct msg_rpc_open_user * msg_open ;
struct msg_rpc_query_user * msg_query ;
struct msg_rpc_close_user * msg_close ;
2005-05-06 19:36:49 +00:00
switch ( m - > type ) {
case rpc_open_user :
2005-07-25 22:57:14 +00:00
msg_open = ( struct msg_rpc_open_user * ) m - > data ;
2005-05-06 19:36:49 +00:00
printf ( " monitor_msg: user opened (rid=%d, access_mask=0x%08x) \n " ,
2005-07-25 22:57:14 +00:00
msg_open - > rid , msg_open - > access_mask ) ;
2005-05-06 19:36:49 +00:00
break ;
case rpc_query_user :
2005-07-25 22:57:14 +00:00
msg_query = ( struct msg_rpc_query_user * ) m - > data ;
printf ( " monitor_msg: user queried (level=%d) \n " , msg_query - > level ) ;
2005-05-06 19:36:49 +00:00
break ;
case rpc_close_user :
2005-07-25 22:57:14 +00:00
msg_close = ( struct msg_rpc_close_user * ) m - > data ;
printf ( " monitor_msg: user closed (rid=%d) \n " , msg_close - > rid ) ;
2005-05-06 19:36:49 +00:00
break ;
}
}
static BOOL test_userinfo_async ( struct dcerpc_pipe * p , TALLOC_CTX * mem_ctx ,
struct policy_handle * domain_handle ,
struct dom_sid2 * domain_sid , const char * user_name ,
uint32_t * rid )
{
NTSTATUS status ;
struct composite_context * c ;
2005-06-11 10:33:31 +00:00
struct libnet_rpc_userinfo user ;
2005-05-06 19:36:49 +00:00
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 = 10 ; /* this should be extended */
2005-06-11 10:33:31 +00:00
printf ( " Testing async libnet_rpc_userinfo \n " ) ;
2005-05-06 19:36:49 +00:00
2005-06-11 10:33:31 +00:00
c = libnet_rpc_userinfo_send ( p , & user , msg_handler ) ;
2005-05-06 19:36:49 +00:00
if ( ! c ) {
2005-06-11 10:33:31 +00:00
printf ( " Failed to call sync libnet_rpc_userinfo_send \n " ) ;
2005-05-06 19:36:49 +00:00
return False ;
}
2005-06-11 10:33:31 +00:00
status = libnet_rpc_userinfo_recv ( c , mem_ctx , & user ) ;
2005-05-06 19:36:49 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-06-11 10:33:31 +00:00
printf ( " Calling async libnet_rpc_userinfo failed - %s \n " , nt_errstr ( status ) ) ;
2005-05-06 19:36:49 +00:00
return False ;
}
return True ;
}
2006-03-25 16:01:28 +00:00
BOOL torture_userinfo ( struct torture_context * torture )
2005-03-01 23:53:18 +00:00
{
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 ;
TALLOC_CTX * mem_ctx ;
BOOL ret = True ;
2005-03-07 12:27:03 +00:00
struct policy_handle h ;
2005-07-08 08:09:02 +00:00
struct lsa_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-12-27 14:28:01 +00:00
& dcerpc_table_samr ) ;
2005-03-01 23:53:18 +00:00
2005-04-22 15:13:01 +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-05-06 19:36:49 +00:00
/*
* Testing synchronous version
*/
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-05-06 19:36:49 +00:00
/*
* Testing asynchronous version and monitor messages
*/
if ( ! test_opendomain ( p , mem_ctx , & h , & name , & sid ) ) {
ret = False ;
goto done ;
}
if ( ! test_create ( p , mem_ctx , & h , TEST_USERNAME , & rid ) ) {
ret = False ;
goto done ;
}
if ( ! test_userinfo_async ( 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 ;
}