2001-12-03 04:23:42 +03:00
/*
Unix SMB / Netbios implementation .
Winbind rpc backend functions
Copyright ( C ) Tim Potter 2000 - 2001
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
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 "winbindd.h"
/* Query display info for a domain. This returns enough information plus a
bit extra to give an overview of domain users for the User Manager
application . */
2001-12-03 14:32:55 +03:00
static NTSTATUS query_user_list ( struct winbindd_domain * domain ,
2001-12-03 09:04:18 +03:00
TALLOC_CTX * mem_ctx ,
uint32 * start_ndx , uint32 * num_entries ,
2001-12-03 14:32:55 +03:00
WINBIND_USERINFO * * info )
2001-12-03 04:23:42 +03:00
{
CLI_POLICY_HND * hnd ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
POLICY_HND dom_pol ;
BOOL got_dom_pol = False ;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED ;
SAM_DISPINFO_CTR ctr ;
SAM_DISPINFO_1 info1 ;
int i ;
2001-12-11 01:10:16 +03:00
* num_entries = 0 ;
2001-12-03 04:23:42 +03:00
/* Get sam handle */
if ( ! ( hnd = cm_get_sam_handle ( domain - > name ) ) )
goto done ;
/* Get domain handle */
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
des_access , & domain - > sid , & dom_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_dom_pol = True ;
ctr . sam . info1 = & info1 ;
/* Query display info level 1 */
result = cli_samr_query_dispinfo ( hnd - > cli , mem_ctx ,
& dom_pol , start_ndx , 1 ,
num_entries , 0xffff , & ctr ) ;
2001-12-03 14:32:55 +03:00
/* now map the result into the WINBIND_USERINFO structure */
( * info ) = ( WINBIND_USERINFO * ) talloc ( mem_ctx , ( * num_entries ) * sizeof ( WINBIND_USERINFO ) ) ;
2001-12-03 04:23:42 +03:00
if ( ! ( * info ) ) {
return NT_STATUS_NO_MEMORY ;
}
for ( i = 0 ; i < * num_entries ; i + + ) {
( * info ) [ i ] . acct_name = unistr2_tdup ( mem_ctx , & info1 . str [ i ] . uni_acct_name ) ;
( * info ) [ i ] . full_name = unistr2_tdup ( mem_ctx , & info1 . str [ i ] . uni_full_name ) ;
( * info ) [ i ] . user_rid = info1 . sam [ i ] . rid_user ;
/* For the moment we set the primary group for every user to be the
Domain Users group . There are serious problems with determining
the actual primary group for large domains . This should really
be made into a ' winbind force group ' smb . conf parameter or
something like that . */
( * info ) [ i ] . group_rid = DOMAIN_GROUP_RID_USERS ;
}
done :
if ( got_dom_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return result ;
}
/* list all domain groups */
2001-12-03 09:04:18 +03:00
static NTSTATUS enum_dom_groups ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
uint32 * start_ndx , uint32 * num_entries ,
struct acct_info * * info )
2001-12-03 04:23:42 +03:00
{
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED ;
CLI_POLICY_HND * hnd ;
POLICY_HND dom_pol ;
NTSTATUS status ;
* num_entries = 0 ;
if ( ! ( hnd = cm_get_sam_handle ( domain - > name ) ) ) {
return NT_STATUS_UNSUCCESSFUL ;
}
status = cli_samr_open_domain ( hnd - > cli , mem_ctx ,
& hnd - > pol , des_access , & domain - > sid , & dom_pol ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = cli_samr_enum_dom_groups ( hnd - > cli , mem_ctx , & dom_pol ,
start_ndx ,
0x8000 , /* buffer size? */
info , num_entries ) ;
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return status ;
}
2001-12-03 11:17:46 +03:00
/* convert a single name to a sid in a domain */
static NTSTATUS name_to_sid ( struct winbindd_domain * domain ,
const char * name ,
DOM_SID * sid ,
enum SID_NAME_USE * type )
{
TALLOC_CTX * mem_ctx ;
CLI_POLICY_HND * hnd ;
NTSTATUS status ;
DOM_SID * sids = NULL ;
uint32 * types = NULL ;
int num_sids ;
if ( ! ( mem_ctx = talloc_init ( ) ) )
return NT_STATUS_NO_MEMORY ;
if ( ! ( hnd = cm_get_lsa_handle ( domain - > name ) ) )
return NT_STATUS_UNSUCCESSFUL ;
status = cli_lsa_lookup_names ( hnd - > cli , mem_ctx , & hnd - > pol , 1 , & name ,
& sids , & types , & num_sids ) ;
/* Return rid and type if lookup successful */
if ( NT_STATUS_IS_OK ( status ) ) {
sid_copy ( sid , & sids [ 0 ] ) ;
* type = types [ 0 ] ;
}
talloc_destroy ( mem_ctx ) ;
return status ;
}
2001-12-03 14:11:14 +03:00
/*
convert a domain SID to a user or group name
*/
2001-12-05 07:48:51 +03:00
static NTSTATUS sid_to_name ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
DOM_SID * sid ,
char * * name ,
enum SID_NAME_USE * type )
2001-12-03 14:11:14 +03:00
{
CLI_POLICY_HND * hnd ;
char * * names ;
uint32 * types ;
int num_names ;
NTSTATUS status ;
if ( ! ( hnd = cm_get_lsa_handle ( domain - > name ) ) )
return NT_STATUS_UNSUCCESSFUL ;
status = cli_lsa_lookup_sids ( hnd - > cli , mem_ctx , & hnd - > pol ,
1 , sid , & names , & types ,
& num_names ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
* type = types [ 0 ] ;
* name = names [ 0 ] ;
DEBUG ( 5 , ( " Mapped sid to %s \n " , * name ) ) ;
}
return status ;
}
2001-12-04 09:17:39 +03:00
/* Lookup user information from a rid or username. */
static NTSTATUS query_user ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2001-12-05 07:48:51 +03:00
uint32 user_rid ,
2001-12-04 09:17:39 +03:00
WINBIND_USERINFO * user_info )
{
CLI_POLICY_HND * hnd ;
NTSTATUS result ;
POLICY_HND dom_pol , user_pol ;
BOOL got_dom_pol = False , got_user_pol = False ;
SAM_USERINFO_CTR * ctr ;
/* Get sam handle */
if ( ! ( hnd = cm_get_sam_handle ( domain - > name ) ) )
goto done ;
/* Get domain handle */
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
SEC_RIGHTS_MAXIMUM_ALLOWED ,
& domain - > sid , & dom_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_dom_pol = True ;
/* Get user handle */
result = cli_samr_open_user ( hnd - > cli , mem_ctx , & dom_pol ,
SEC_RIGHTS_MAXIMUM_ALLOWED , user_rid , & user_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
/* Get user info */
result = cli_samr_query_userinfo ( hnd - > cli , mem_ctx , & user_pol ,
0x15 , & ctr ) ;
cli_samr_close ( hnd - > cli , mem_ctx , & user_pol ) ;
user_info - > group_rid = ctr - > info . id21 - > group_rid ;
2001-12-05 07:48:51 +03:00
user_info - > acct_name = unistr2_tdup ( mem_ctx ,
& ctr - > info . id21 - > uni_user_name ) ;
2001-12-04 09:17:39 +03:00
user_info - > full_name = unistr2_tdup ( mem_ctx ,
& ctr - > info . id21 - > uni_full_name ) ;
done :
/* Clean up policy handles */
if ( got_user_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & user_pol ) ;
if ( got_dom_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return result ;
}
2001-12-04 09:46:53 +03:00
/* Lookup groups a user is a member of. I wish Unix had a call like this! */
static NTSTATUS lookup_usergroups ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2001-12-05 07:48:51 +03:00
uint32 user_rid ,
2001-12-04 15:10:05 +03:00
uint32 * num_groups , uint32 * * user_gids )
2001-12-04 09:46:53 +03:00
{
CLI_POLICY_HND * hnd ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
POLICY_HND dom_pol , user_pol ;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED ;
BOOL got_dom_pol = False , got_user_pol = False ;
DOM_GID * user_groups ;
int i ;
2001-12-11 01:10:16 +03:00
* num_groups = 0 ;
2001-12-04 09:46:53 +03:00
/* Get sam handle */
if ( ! ( hnd = cm_get_sam_handle ( domain - > name ) ) )
goto done ;
/* Get domain handle */
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
des_access , & domain - > sid , & dom_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_dom_pol = True ;
/* Get user handle */
result = cli_samr_open_user ( hnd - > cli , mem_ctx , & dom_pol ,
des_access , user_rid , & user_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_user_pol = True ;
/* Query user rids */
result = cli_samr_query_usergroups ( hnd - > cli , mem_ctx , & user_pol ,
num_groups , & user_groups ) ;
if ( ! NT_STATUS_IS_OK ( result ) | | ( * num_groups ) = = 0 )
goto done ;
( * user_gids ) = talloc ( mem_ctx , sizeof ( uint32 ) * ( * num_groups ) ) ;
for ( i = 0 ; i < ( * num_groups ) ; i + + ) {
( * user_gids ) [ i ] = user_groups [ i ] . g_rid ;
}
done :
/* Clean up policy handles */
if ( got_user_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & user_pol ) ;
if ( got_dom_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return result ;
}
2001-12-03 04:23:42 +03:00
2001-12-05 07:48:51 +03:00
/* Lookup group membership given a rid. */
static NTSTATUS lookup_groupmem ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
uint32 group_rid , uint32 * num_names ,
uint32 * * rid_mem , char * * * names ,
uint32 * * name_types )
{
CLI_POLICY_HND * hnd ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
uint32 i , total_names = 0 ;
POLICY_HND dom_pol , group_pol ;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED ;
BOOL got_dom_pol = False , got_group_pol = False ;
2001-12-11 01:10:16 +03:00
* num_names = 0 ;
2001-12-05 07:48:51 +03:00
/* Get sam handle */
if ( ! ( hnd = cm_get_sam_handle ( domain - > name ) ) )
goto done ;
/* Get domain handle */
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
des_access , & domain - > sid , & dom_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_dom_pol = True ;
/* Get group handle */
result = cli_samr_open_group ( hnd - > cli , mem_ctx , & dom_pol ,
des_access , group_rid , & group_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_group_pol = True ;
/* Step #1: Get a list of user rids that are the members of the
group . */
result = cli_samr_query_groupmem ( hnd - > cli , mem_ctx ,
& group_pol , num_names , rid_mem ,
name_types ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
/* Step #2: Convert list of rids into list of usernames. Do this
in bunches of ~ 1000 to avoid crashing NT4 . It looks like there
is a buffer overflow or something like that lurking around
somewhere . */
# define MAX_LOOKUP_RIDS 900
* names = talloc ( mem_ctx , * num_names * sizeof ( char * ) ) ;
* name_types = talloc ( mem_ctx , * num_names * sizeof ( uint32 ) ) ;
for ( i = 0 ; i < * num_names ; i + = MAX_LOOKUP_RIDS ) {
int num_lookup_rids = MIN ( * num_names - i , MAX_LOOKUP_RIDS ) ;
uint32 tmp_num_names = 0 ;
char * * tmp_names = NULL ;
uint32 * tmp_types = NULL ;
/* Lookup a chunk of rids */
result = cli_samr_lookup_rids ( hnd - > cli , mem_ctx ,
& dom_pol , 1000 , /* flags */
num_lookup_rids ,
& ( * rid_mem ) [ i ] ,
& tmp_num_names ,
& tmp_names , & tmp_types ) ;
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
/* Copy result into array. The talloc system will take
care of freeing the temporary arrays later on . */
memcpy ( & ( * names ) [ i ] , tmp_names , sizeof ( char * ) *
tmp_num_names ) ;
memcpy ( & ( * name_types ) [ i ] , tmp_types , sizeof ( uint32 ) *
tmp_num_names ) ;
total_names + = tmp_num_names ;
}
* num_names = total_names ;
done :
if ( got_group_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & group_pol ) ;
if ( got_dom_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return result ;
}
2001-12-05 10:52:44 +03:00
/* find the sequence number for a domain */
2001-12-10 02:59:42 +03:00
static NTSTATUS sequence_number ( struct winbindd_domain * domain , uint32 * seq )
2001-12-05 10:52:44 +03:00
{
TALLOC_CTX * mem_ctx ;
CLI_POLICY_HND * hnd ;
SAM_UNK_CTR ctr ;
uint16 switch_value = 2 ;
NTSTATUS result ;
uint32 seqnum = DOM_SEQUENCE_NONE ;
POLICY_HND dom_pol ;
BOOL got_dom_pol = False ;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED ;
2001-12-10 02:59:42 +03:00
* seq = DOM_SEQUENCE_NONE ;
2001-12-05 10:52:44 +03:00
if ( ! ( mem_ctx = talloc_init ( ) ) )
2001-12-10 02:59:42 +03:00
return NT_STATUS_NO_MEMORY ;
2001-12-05 10:52:44 +03:00
/* Get sam handle */
if ( ! ( hnd = cm_get_sam_handle ( domain - > name ) ) )
goto done ;
/* Get domain handle */
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
2001-12-10 02:59:42 +03:00
des_access , & domain - > sid , & dom_pol ) ;
2001-12-05 10:52:44 +03:00
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_dom_pol = True ;
/* Query domain info */
result = cli_samr_query_dom_info ( hnd - > cli , mem_ctx , & dom_pol ,
2001-12-10 02:59:42 +03:00
switch_value , & ctr ) ;
2001-12-05 10:52:44 +03:00
if ( NT_STATUS_IS_OK ( result ) ) {
seqnum = ctr . info . inf2 . seq_num ;
DEBUG ( 10 , ( " domain_sequence_number: for domain %s is %u \n " , domain - > name , ( unsigned ) seqnum ) ) ;
} else {
DEBUG ( 10 , ( " domain_sequence_number: failed to get sequence number (%u) for domain %s \n " ,
( unsigned ) seqnum , domain - > name ) ) ;
}
done :
if ( got_dom_pol )
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
talloc_destroy ( mem_ctx ) ;
2001-12-10 02:59:42 +03:00
* seq = seqnum ;
return result ;
2001-12-05 10:52:44 +03:00
}
2001-12-10 05:25:19 +03:00
/* get a list of trusted domains */
static NTSTATUS trusted_domains ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
uint32 * num_domains ,
char * * * names ,
DOM_SID * * dom_sids )
{
CLI_POLICY_HND * hnd ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
uint32 enum_ctx = 0 ;
2001-12-11 01:10:16 +03:00
* num_domains = 0 ;
2001-12-10 05:25:19 +03:00
if ( ! ( hnd = cm_get_lsa_handle ( lp_workgroup ( ) ) ) )
goto done ;
result = cli_lsa_enum_trust_dom ( hnd - > cli , mem_ctx ,
& hnd - > pol , & enum_ctx , num_domains ,
names , dom_sids ) ;
done :
return result ;
}
/* find the domain sid for a domain */
static NTSTATUS domain_sid ( struct winbindd_domain * domain , DOM_SID * sid )
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
TALLOC_CTX * mem_ctx ;
CLI_POLICY_HND * hnd ;
fstring level5_dom ;
if ( ! ( mem_ctx = talloc_init ( ) ) )
return NT_STATUS_NO_MEMORY ;
/* Get sam handle */
if ( ! ( hnd = cm_get_lsa_handle ( domain - > name ) ) )
goto done ;
status = cli_lsa_query_info_policy ( hnd - > cli , mem_ctx ,
& hnd - > pol , 0x05 , level5_dom , sid ) ;
done :
talloc_destroy ( mem_ctx ) ;
return status ;
}
2001-12-05 07:48:51 +03:00
2001-12-03 04:23:42 +03:00
/* the rpc backend methods are exposed via this structure */
struct winbindd_methods msrpc_methods = {
2001-12-10 09:05:21 +03:00
False ,
2001-12-03 14:32:55 +03:00
query_user_list ,
2001-12-03 11:17:46 +03:00
enum_dom_groups ,
2001-12-03 14:11:14 +03:00
name_to_sid ,
2001-12-05 07:48:51 +03:00
sid_to_name ,
2001-12-04 09:46:53 +03:00
query_user ,
2001-12-05 07:48:51 +03:00
lookup_usergroups ,
2001-12-05 10:52:44 +03:00
lookup_groupmem ,
2001-12-10 05:25:19 +03:00
sequence_number ,
trusted_domains ,
domain_sid
2001-12-03 04:23:42 +03:00
} ;