2007-08-20 01:07:11 +04:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Rafal Szczesniak 2007
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
/*
a composite function for getting group information via samr pipe
*/
# include "includes.h"
# include "libcli/composite/composite.h"
# include "librpc/gen_ndr/security.h"
# include "libcli/security/security.h"
2008-12-24 00:11:21 +03:00
# include "libnet/libnet.h"
2007-08-20 01:07:11 +04:00
# include "librpc/gen_ndr/ndr_samr_c.h"
struct groupinfo_state {
2014-01-14 15:11:17 +04:00
struct dcerpc_binding_handle * binding_handle ;
2007-08-20 01:07:11 +04:00
struct policy_handle domain_handle ;
struct policy_handle group_handle ;
uint16_t level ;
struct samr_LookupNames lookup ;
struct samr_OpenGroup opengroup ;
struct samr_QueryGroupInfo querygroupinfo ;
struct samr_Close samrclose ;
union samr_GroupInfo * info ;
/* information about the progress */
void ( * monitor_fn ) ( struct monitor_msg * ) ;
} ;
2010-03-08 18:32:45 +03:00
static void continue_groupinfo_lookup ( struct tevent_req * subreq ) ;
static void continue_groupinfo_opengroup ( struct tevent_req * subreq ) ;
static void continue_groupinfo_getgroup ( struct tevent_req * subreq ) ;
static void continue_groupinfo_closegroup ( struct tevent_req * subreq ) ;
2007-08-20 01:07:11 +04:00
/**
* Stage 1 ( optional ) : Look for a group name in SAM server .
*/
2010-03-08 18:32:45 +03:00
static void continue_groupinfo_lookup ( struct tevent_req * subreq )
2007-08-20 01:07:11 +04:00
{
struct composite_context * c ;
struct groupinfo_state * s ;
struct monitor_msg msg ;
struct msg_rpc_lookup_name * msg_lookup ;
2010-03-08 18:32:45 +03:00
c = tevent_req_callback_data ( subreq , struct composite_context ) ;
2007-08-20 01:07:11 +04:00
s = talloc_get_type ( c - > private_data , struct groupinfo_state ) ;
/* receive samr_Lookup reply */
2010-03-08 18:32:45 +03:00
c - > status = dcerpc_samr_LookupNames_r_recv ( subreq , s ) ;
TALLOC_FREE ( subreq ) ;
2007-08-20 01:07:11 +04:00
if ( ! composite_is_ok ( c ) ) return ;
/* there could be a problem with name resolving itself */
if ( ! NT_STATUS_IS_OK ( s - > lookup . out . result ) ) {
composite_error ( c , s - > lookup . out . result ) ;
return ;
}
/* issue a monitor message */
if ( s - > monitor_fn ) {
msg . type = mon_SamrLookupName ;
msg_lookup = talloc ( s , struct msg_rpc_lookup_name ) ;
2008-11-05 16:28:17 +03:00
msg_lookup - > rid = s - > lookup . out . rids - > ids ;
msg_lookup - > count = s - > lookup . out . rids - > count ;
2007-08-20 01:07:11 +04:00
msg . data = ( void * ) msg_lookup ;
msg . data_size = sizeof ( * msg_lookup ) ;
s - > monitor_fn ( & msg ) ;
}
/* have we actually got name resolved
- we ' re looking for only one at the moment */
2013-11-08 09:40:55 +04:00
if ( s - > lookup . out . rids - > count ! = s - > lookup . in . num_names ) {
composite_error ( c , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
return ;
}
if ( s - > lookup . out . types - > count ! = s - > lookup . in . num_names ) {
composite_error ( c , NT_STATUS_INVALID_NETWORK_RESPONSE ) ;
2012-04-23 11:27:02 +04:00
return ;
2007-08-20 01:07:11 +04:00
}
/* TODO: find proper status code for more than one rid found */
/* prepare parameters for LookupNames */
s - > opengroup . in . domain_handle = & s - > domain_handle ;
s - > opengroup . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
2008-11-05 16:28:17 +03:00
s - > opengroup . in . rid = s - > lookup . out . rids - > ids [ 0 ] ;
2007-08-20 01:07:11 +04:00
s - > opengroup . out . group_handle = & s - > group_handle ;
/* send request */
2010-03-08 18:32:45 +03:00
subreq = dcerpc_samr_OpenGroup_r_send ( s , c - > event_ctx ,
2014-01-14 15:11:17 +04:00
s - > binding_handle ,
2010-03-08 18:32:45 +03:00
& s - > opengroup ) ;
if ( composite_nomem ( subreq , c ) ) return ;
2007-08-20 01:07:11 +04:00
2010-03-08 18:32:45 +03:00
tevent_req_set_callback ( subreq , continue_groupinfo_opengroup , c ) ;
2007-08-20 01:07:11 +04:00
}
/**
* Stage 2 : Open group policy handle .
*/
2010-03-08 18:32:45 +03:00
static void continue_groupinfo_opengroup ( struct tevent_req * subreq )
2007-08-20 01:07:11 +04:00
{
struct composite_context * c ;
struct groupinfo_state * s ;
struct monitor_msg msg ;
struct msg_rpc_open_group * msg_open ;
2010-03-08 18:32:45 +03:00
c = tevent_req_callback_data ( subreq , struct composite_context ) ;
2007-08-20 01:07:11 +04:00
s = talloc_get_type ( c - > private_data , struct groupinfo_state ) ;
/* receive samr_OpenGroup reply */
2010-03-08 18:32:45 +03:00
c - > status = dcerpc_samr_OpenGroup_r_recv ( subreq , s ) ;
TALLOC_FREE ( subreq ) ;
2007-08-20 01:07:11 +04:00
if ( ! composite_is_ok ( c ) ) return ;
2012-04-23 07:48:49 +04:00
if ( ! NT_STATUS_IS_OK ( s - > opengroup . out . result ) ) {
composite_error ( c , s - > opengroup . out . result ) ;
2007-08-20 01:07:11 +04:00
return ;
}
/* issue a monitor message */
if ( s - > monitor_fn ) {
msg . type = mon_SamrOpenGroup ;
msg_open = talloc ( s , struct msg_rpc_open_group ) ;
msg_open - > rid = s - > opengroup . in . rid ;
msg_open - > access_mask = s - > opengroup . in . access_mask ;
msg . data = ( void * ) msg_open ;
msg . data_size = sizeof ( * msg_open ) ;
s - > monitor_fn ( & msg ) ;
}
/* prepare parameters for QueryGroupInfo call */
s - > querygroupinfo . in . group_handle = & s - > group_handle ;
s - > querygroupinfo . in . level = s - > level ;
2008-11-10 16:15:33 +03:00
s - > querygroupinfo . out . info = talloc ( s , union samr_GroupInfo * ) ;
if ( composite_nomem ( s - > querygroupinfo . out . info , c ) ) return ;
2007-08-20 01:07:11 +04:00
/* queue rpc call, set event handling and new state */
2010-03-08 18:32:45 +03:00
subreq = dcerpc_samr_QueryGroupInfo_r_send ( s ,
c - > event_ctx ,
2014-01-14 15:11:17 +04:00
s - > binding_handle ,
2010-03-08 18:32:45 +03:00
& s - > querygroupinfo ) ;
if ( composite_nomem ( subreq , c ) ) return ;
2007-08-20 01:07:11 +04:00
2010-03-08 18:32:45 +03:00
tevent_req_set_callback ( subreq , continue_groupinfo_getgroup , c ) ;
2007-08-20 01:07:11 +04:00
}
/**
* Stage 3 : Get requested group information .
*/
2010-03-08 18:32:45 +03:00
static void continue_groupinfo_getgroup ( struct tevent_req * subreq )
2007-08-20 01:07:11 +04:00
{
struct composite_context * c ;
struct groupinfo_state * s ;
struct monitor_msg msg ;
struct msg_rpc_query_group * msg_query ;
2010-03-08 18:32:45 +03:00
c = tevent_req_callback_data ( subreq , struct composite_context ) ;
2007-08-20 01:07:11 +04:00
s = talloc_get_type ( c - > private_data , struct groupinfo_state ) ;
/* receive samr_QueryGroupInfo reply */
2010-03-08 18:32:45 +03:00
c - > status = dcerpc_samr_QueryGroupInfo_r_recv ( subreq , s ) ;
TALLOC_FREE ( subreq ) ;
2007-08-20 01:07:11 +04:00
if ( ! composite_is_ok ( c ) ) return ;
/* check if querygroup itself went ok */
if ( ! NT_STATUS_IS_OK ( s - > querygroupinfo . out . result ) ) {
composite_error ( c , s - > querygroupinfo . out . result ) ;
return ;
}
2008-11-10 16:15:33 +03:00
s - > info = talloc_steal ( s , * s - > querygroupinfo . out . info ) ;
2007-08-20 01:07:11 +04:00
/* issue a monitor message */
if ( s - > monitor_fn ) {
msg . type = mon_SamrQueryGroup ;
msg_query = talloc ( s , struct msg_rpc_query_group ) ;
msg_query - > level = s - > querygroupinfo . in . level ;
msg . data = ( void * ) msg_query ;
msg . data_size = sizeof ( * msg_query ) ;
s - > monitor_fn ( & msg ) ;
}
/* prepare arguments for Close call */
s - > samrclose . in . handle = & s - > group_handle ;
s - > samrclose . out . handle = & s - > group_handle ;
/* queue rpc call, set event handling and new state */
2010-03-08 18:32:45 +03:00
subreq = dcerpc_samr_Close_r_send ( s , c - > event_ctx ,
2014-01-14 15:11:17 +04:00
s - > binding_handle ,
2010-03-08 18:32:45 +03:00
& s - > samrclose ) ;
if ( composite_nomem ( subreq , c ) ) return ;
2007-08-20 01:07:11 +04:00
2010-03-08 18:32:45 +03:00
tevent_req_set_callback ( subreq , continue_groupinfo_closegroup , c ) ;
2007-08-20 01:07:11 +04:00
}
/**
* Stage 4 : Close policy handle associated with opened group .
*/
2010-03-08 18:32:45 +03:00
static void continue_groupinfo_closegroup ( struct tevent_req * subreq )
2007-08-20 01:07:11 +04:00
{
struct composite_context * c ;
struct groupinfo_state * s ;
struct monitor_msg msg ;
struct msg_rpc_close_group * msg_close ;
2010-03-08 18:32:45 +03:00
c = tevent_req_callback_data ( subreq , struct composite_context ) ;
2007-08-20 01:07:11 +04:00
s = talloc_get_type ( c - > private_data , struct groupinfo_state ) ;
/* receive samr_Close reply */
2010-03-08 18:32:45 +03:00
c - > status = dcerpc_samr_Close_r_recv ( subreq , s ) ;
TALLOC_FREE ( subreq ) ;
2007-08-20 01:07:11 +04:00
if ( ! composite_is_ok ( c ) ) return ;
if ( ! NT_STATUS_IS_OK ( s - > samrclose . out . result ) ) {
composite_error ( c , s - > samrclose . out . result ) ;
return ;
}
/* issue a monitor message */
if ( s - > monitor_fn ) {
msg . type = mon_SamrClose ;
msg_close = talloc ( s , struct msg_rpc_close_group ) ;
msg_close - > rid = s - > opengroup . in . rid ;
msg . data = ( void * ) msg_close ;
msg . data_size = sizeof ( * msg_close ) ;
s - > monitor_fn ( & msg ) ;
}
composite_done ( c ) ;
}
/**
* Sends asynchronous groupinfo request
*
* @ param p dce / rpc call pipe
* @ param io arguments and results of the call
*/
2014-01-14 15:11:17 +04:00
struct composite_context * libnet_rpc_groupinfo_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct dcerpc_binding_handle * b ,
2007-08-20 01:07:11 +04:00
struct libnet_rpc_groupinfo * io ,
void ( * monitor ) ( struct monitor_msg * ) )
{
struct composite_context * c ;
struct groupinfo_state * s ;
struct dom_sid * sid ;
2010-03-08 18:32:45 +03:00
struct tevent_req * subreq ;
2007-08-20 01:07:11 +04:00
2014-01-14 15:11:17 +04:00
if ( ! b | | ! io ) return NULL ;
2007-08-20 01:07:11 +04:00
2014-01-14 15:11:17 +04:00
c = composite_create ( mem_ctx , ev ) ;
2007-08-20 01:07:11 +04:00
if ( c = = NULL ) return c ;
s = talloc_zero ( c , struct groupinfo_state ) ;
if ( composite_nomem ( s , c ) ) return c ;
c - > private_data = s ;
s - > level = io - > in . level ;
2014-01-14 15:11:17 +04:00
s - > binding_handle = b ;
2007-08-20 01:07:11 +04:00
s - > domain_handle = io - > in . domain_handle ;
s - > monitor_fn = monitor ;
if ( io - > in . sid ) {
sid = dom_sid_parse_talloc ( s , io - > in . sid ) ;
if ( composite_nomem ( sid , c ) ) return c ;
s - > opengroup . in . domain_handle = & s - > domain_handle ;
s - > opengroup . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
s - > opengroup . in . rid = sid - > sub_auths [ sid - > num_auths - 1 ] ;
s - > opengroup . out . group_handle = & s - > group_handle ;
/* send request */
2010-03-08 18:32:45 +03:00
subreq = dcerpc_samr_OpenGroup_r_send ( s , c - > event_ctx ,
2014-01-14 15:11:17 +04:00
s - > binding_handle ,
2010-03-08 18:32:45 +03:00
& s - > opengroup ) ;
if ( composite_nomem ( subreq , c ) ) return c ;
2007-08-20 01:07:11 +04:00
2010-03-08 18:32:45 +03:00
tevent_req_set_callback ( subreq , continue_groupinfo_opengroup , c ) ;
2007-08-20 01:07:11 +04:00
} else {
/* preparing parameters to send rpc request */
s - > lookup . in . domain_handle = & s - > domain_handle ;
s - > lookup . in . num_names = 1 ;
s - > lookup . in . names = talloc_array ( s , struct lsa_String , 1 ) ;
if ( composite_nomem ( s - > lookup . in . names , c ) ) return c ;
s - > lookup . in . names [ 0 ] . string = talloc_strdup ( s , io - > in . groupname ) ;
if ( composite_nomem ( s - > lookup . in . names [ 0 ] . string , c ) ) return c ;
2008-11-05 16:28:17 +03:00
s - > lookup . out . rids = talloc_zero ( s , struct samr_Ids ) ;
s - > lookup . out . types = talloc_zero ( s , struct samr_Ids ) ;
if ( composite_nomem ( s - > lookup . out . rids , c ) ) return c ;
if ( composite_nomem ( s - > lookup . out . types , c ) ) return c ;
2007-08-20 01:07:11 +04:00
/* send request */
2010-03-08 18:32:45 +03:00
subreq = dcerpc_samr_LookupNames_r_send ( s , c - > event_ctx ,
2014-01-14 15:11:17 +04:00
s - > binding_handle ,
2010-03-08 18:32:45 +03:00
& s - > lookup ) ;
if ( composite_nomem ( subreq , c ) ) return c ;
2007-08-20 01:07:11 +04:00
2010-03-08 18:32:45 +03:00
tevent_req_set_callback ( subreq , continue_groupinfo_lookup , c ) ;
2007-08-20 01:07:11 +04:00
}
return c ;
}
/**
* Waits for and receives result of asynchronous groupinfo call
*
* @ param c composite context returned by asynchronous groupinfo call
* @ param mem_ctx memory context of the call
* @ param io pointer to results ( and arguments ) of the call
* @ return nt status code of execution
*/
NTSTATUS libnet_rpc_groupinfo_recv ( struct composite_context * c , TALLOC_CTX * mem_ctx ,
struct libnet_rpc_groupinfo * io )
{
NTSTATUS status ;
struct groupinfo_state * s ;
/* wait for results of sending request */
status = composite_wait ( c ) ;
if ( NT_STATUS_IS_OK ( status ) & & io ) {
s = talloc_get_type ( c - > private_data , struct groupinfo_state ) ;
talloc_steal ( mem_ctx , s - > info ) ;
io - > out . info = * s - > info ;
}
/* memory context associated to composite context is no longer needed */
talloc_free ( c ) ;
return status ;
}
/**
* Synchronous version of groupinfo call
*
* @ param pipe dce / rpc call pipe
* @ param mem_ctx memory context for the call
* @ param io arguments and results of the call
* @ return nt status code of execution
*/
2014-01-14 15:11:17 +04:00
NTSTATUS libnet_rpc_groupinfo ( struct tevent_context * ev ,
struct dcerpc_binding_handle * b ,
2007-08-20 01:07:11 +04:00
TALLOC_CTX * mem_ctx ,
struct libnet_rpc_groupinfo * io )
{
2014-01-14 15:11:17 +04:00
struct composite_context * c = libnet_rpc_groupinfo_send ( mem_ctx , ev , b ,
2014-01-14 15:11:17 +04:00
io , NULL ) ;
2007-08-20 01:07:11 +04:00
return libnet_rpc_groupinfo_recv ( c , mem_ctx , io ) ;
}