2001-12-03 04:23:42 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-12-03 04:23:42 +03:00
Winbind rpc backend functions
2003-04-23 15:54:56 +04:00
Copyright ( C ) Tim Potter 2000 - 2001 , 2003
2001-12-03 04:23:42 +03:00
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"
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2003-04-23 15:54:56 +04:00
2001-12-03 04:23:42 +03:00
/* 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 ,
2001-12-11 03:03:58 +03:00
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 ;
2003-04-23 15:54:56 +04:00
unsigned int i , start_idx , retry ;
2001-12-03 04:23:42 +03:00
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " rpc: query_user_list \n " ) ) ;
2001-12-11 01:10:16 +03:00
* num_entries = 0 ;
2001-12-11 03:03:58 +03:00
* info = NULL ;
2001-12-11 01:10:16 +03:00
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-04-23 15:54:56 +04:00
/* Get sam handle */
2003-06-21 08:05:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = cm_get_sam_handle ( domain - > name , & hnd ) ) )
return result ;
2001-12-03 04:23:42 +03:00
2003-02-15 04:34:37 +03:00
/* Get domain handle */
2001-12-03 04:23:42 +03:00
2003-02-15 04:34:37 +03:00
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
des_access , & domain - > sid , & dom_pol ) ;
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & & hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-03 04:23:42 +03:00
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_dom_pol = True ;
2003-04-23 15:54:56 +04:00
i = start_idx = 0 ;
2001-12-11 03:03:58 +03:00
do {
2002-01-31 15:47:42 +03:00
TALLOC_CTX * ctx2 ;
2003-04-23 15:54:56 +04:00
char * * dom_users ;
uint32 num_dom_users , * dom_rids , j , size = 0xffff ;
uint16 acb_mask = ACB_NORMAL ;
2002-01-31 15:47:42 +03:00
2003-04-23 15:54:56 +04:00
if ( ! ( ctx2 = talloc_init ( " winbindd enum_users " ) ) ) {
2002-04-04 06:39:57 +04:00
result = NT_STATUS_NO_MEMORY ;
goto done ;
2003-04-23 15:54:56 +04:00
}
2003-01-29 23:15:35 +03:00
2003-04-23 15:54:56 +04:00
result = cli_samr_enum_dom_users (
hnd - > cli , ctx2 , & dom_pol , & start_idx , acb_mask ,
size , & dom_users , & dom_rids , & num_dom_users ) ;
2003-01-29 23:15:35 +03:00
2003-04-23 15:54:56 +04:00
* num_entries + = num_dom_users ;
2001-12-11 03:03:58 +03:00
2003-04-23 15:54:56 +04:00
* info = talloc_realloc (
mem_ctx , * info ,
( * num_entries ) * sizeof ( WINBIND_USERINFO ) ) ;
2001-12-11 03:03:58 +03:00
if ( ! ( * info ) ) {
2002-04-04 06:39:57 +04:00
result = NT_STATUS_NO_MEMORY ;
talloc_destroy ( ctx2 ) ;
goto done ;
2001-12-11 03:03:58 +03:00
}
2003-04-23 15:54:56 +04:00
for ( j = 0 ; j < num_dom_users ; i + + , j + + ) {
( * info ) [ i ] . acct_name =
talloc_strdup ( mem_ctx , dom_users [ j ] ) ;
( * info ) [ i ] . full_name = talloc_strdup ( mem_ctx , " " ) ;
( * info ) [ i ] . user_sid = rid_to_talloced_sid ( domain , mem_ctx , dom_rids [ j ] ) ;
2001-12-11 03:03:58 +03:00
/* 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 . */
2003-04-23 15:54:56 +04:00
( * info ) [ i ] . group_sid
= rid_to_talloced_sid ( domain ,
mem_ctx ,
DOMAIN_GROUP_RID_USERS ) ;
2001-12-11 03:03:58 +03:00
}
2002-01-31 15:47:42 +03:00
talloc_destroy ( ctx2 ) ;
2003-04-23 15:54:56 +04:00
2001-12-11 03:03:58 +03:00
} while ( NT_STATUS_EQUAL ( result , STATUS_MORE_ENTRIES ) ) ;
2001-12-03 04:23:42 +03:00
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 ,
2001-12-11 04:04:13 +03:00
uint32 * num_entries ,
2001-12-03 09:04:18 +03:00
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 ;
2003-01-06 10:29:38 +03:00
uint32 start = 0 ;
2003-02-15 04:34:37 +03:00
int retry ;
2003-06-21 08:05:01 +04:00
NTSTATUS result ;
2001-12-03 04:23:42 +03:00
* num_entries = 0 ;
2001-12-11 04:04:13 +03:00
* info = NULL ;
2001-12-03 04:23:42 +03:00
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " rpc: enum_dom_groups \n " ) ) ;
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = cm_get_sam_handle ( domain - > name , & hnd ) ) )
return result ;
2003-02-15 04:34:37 +03:00
status = cli_samr_open_domain ( hnd - > cli , mem_ctx ,
& hnd - > pol , des_access , & domain - > sid , & dom_pol ) ;
} while ( ! NT_STATUS_IS_OK ( status ) & & ( retry + + < 1 ) & & hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-03 04:23:42 +03:00
2003-02-15 04:34:37 +03:00
if ( ! NT_STATUS_IS_OK ( status ) )
2001-12-03 04:23:42 +03:00
return status ;
2001-12-11 04:04:13 +03:00
do {
struct acct_info * info2 = NULL ;
2003-01-06 10:29:38 +03:00
uint32 count = 0 ;
2001-12-11 04:04:13 +03:00
TALLOC_CTX * mem_ctx2 ;
2002-12-20 23:21:31 +03:00
mem_ctx2 = talloc_init ( " enum_dom_groups[rpc] " ) ;
2001-12-11 04:04:13 +03:00
2003-01-06 10:29:38 +03:00
/* start is updated by this call. */
2001-12-11 04:04:13 +03:00
status = cli_samr_enum_dom_groups ( hnd - > cli , mem_ctx2 , & dom_pol ,
& start ,
0xFFFF , /* buffer size? */
& info2 , & count ) ;
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) {
talloc_destroy ( mem_ctx2 ) ;
break ;
}
( * info ) = talloc_realloc ( mem_ctx , * info ,
sizeof ( * * info ) * ( ( * num_entries ) + count ) ) ;
if ( ! * info ) {
talloc_destroy ( mem_ctx2 ) ;
2002-04-04 06:39:57 +04:00
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
2001-12-11 04:04:13 +03:00
return NT_STATUS_NO_MEMORY ;
}
memcpy ( & ( * info ) [ * num_entries ] , info2 , count * sizeof ( * info2 ) ) ;
( * num_entries ) + = count ;
talloc_destroy ( mem_ctx2 ) ;
} while ( NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) ;
2001-12-03 04:23:42 +03:00
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return status ;
}
2002-10-08 22:32:42 +04:00
/* List all domain groups */
static NTSTATUS enum_local_groups ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
uint32 * num_entries ,
struct acct_info * * info )
{
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED ;
CLI_POLICY_HND * hnd ;
POLICY_HND dom_pol ;
NTSTATUS result ;
2003-02-15 04:34:37 +03:00
int retry ;
2002-10-08 22:32:42 +04:00
* num_entries = 0 ;
* info = NULL ;
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = cm_get_sam_handle ( domain - > name , & hnd ) ) )
return result ;
2003-02-15 04:34:37 +03:00
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
des_access , & domain - > sid , & dom_pol ) ;
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & & hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2002-10-08 22:32:42 +04:00
2003-02-15 04:34:37 +03:00
if ( ! NT_STATUS_IS_OK ( result ) )
2002-10-08 22:32:42 +04:00
return result ;
do {
struct acct_info * info2 = NULL ;
uint32 count = 0 , start = * num_entries ;
TALLOC_CTX * mem_ctx2 ;
2002-12-20 23:21:31 +03:00
mem_ctx2 = talloc_init ( " enum_dom_local_groups[rpc] " ) ;
2002-10-08 22:32:42 +04:00
result = cli_samr_enum_als_groups ( hnd - > cli , mem_ctx2 , & dom_pol ,
& start , 0xFFFF , & info2 , & count ) ;
if ( ! NT_STATUS_IS_OK ( result )
& & ! NT_STATUS_EQUAL ( result , STATUS_MORE_ENTRIES ) )
{
talloc_destroy ( mem_ctx2 ) ;
break ;
}
( * info ) = talloc_realloc ( mem_ctx , * info ,
sizeof ( * * info ) * ( ( * num_entries ) + count ) ) ;
if ( ! * info ) {
talloc_destroy ( mem_ctx2 ) ;
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return NT_STATUS_NO_MEMORY ;
}
memcpy ( & ( * info ) [ * num_entries ] , info2 , count * sizeof ( * info2 ) ) ;
( * num_entries ) + = count ;
talloc_destroy ( mem_ctx2 ) ;
} while ( NT_STATUS_EQUAL ( result , STATUS_MORE_ENTRIES ) ) ;
cli_samr_close ( hnd - > cli , mem_ctx , & dom_pol ) ;
return result ;
}
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 ,
2003-04-23 15:54:56 +04:00
TALLOC_CTX * mem_ctx ,
2001-12-03 11:17:46 +03:00
const char * name ,
DOM_SID * sid ,
enum SID_NAME_USE * type )
{
CLI_POLICY_HND * hnd ;
2003-06-21 08:05:01 +04:00
NTSTATUS result ;
2001-12-03 11:17:46 +03:00
DOM_SID * sids = NULL ;
uint32 * types = NULL ;
2002-01-26 14:48:42 +03:00
const char * full_name ;
2003-02-15 04:34:37 +03:00
int retry ;
2001-12-03 11:17:46 +03:00
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " rpc: name_to_sid name=%s \n " , name ) ) ;
2002-01-26 14:48:42 +03:00
full_name = talloc_asprintf ( mem_ctx , " %s \\ %s " , domain - > name , name ) ;
if ( ! full_name ) {
DEBUG ( 0 , ( " talloc_asprintf failed! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
2003-06-21 08:05:01 +04:00
DEBUG ( 3 , ( " name_to_sid [rpc] %s for domain %s \n " , name , domain - > name ) ) ;
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = cm_get_lsa_handle ( domain - > name , & hnd ) ) ) {
return result ;
2003-02-15 04:34:37 +03:00
}
2003-06-21 08:05:01 +04:00
result = cli_lsa_lookup_names ( hnd - > cli , mem_ctx , & hnd - > pol , 1 ,
2003-02-15 04:34:37 +03:00
& full_name , & sids , & types ) ;
2003-06-21 08:05:01 +04:00
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & &
hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-03 11:17:46 +03:00
2002-07-15 14:35:28 +04:00
/* Return rid and type if lookup successful */
2003-06-21 08:05:01 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
2001-12-03 11:17:46 +03:00
sid_copy ( sid , & sids [ 0 ] ) ;
* type = types [ 0 ] ;
}
2003-06-21 08:05:01 +04:00
return result ;
2001-12-03 11:17:46 +03:00
}
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 ;
2002-01-20 04:24:59 +03:00
char * * domains ;
2001-12-03 14:11:14 +03:00
char * * names ;
uint32 * types ;
2003-06-21 08:05:01 +04:00
NTSTATUS result ;
2003-02-15 04:34:37 +03:00
int retry ;
2001-12-03 14:11:14 +03:00
2003-06-21 08:05:01 +04:00
DEBUG ( 3 , ( " sid_to_name [rpc] %s for domain %s \n " , sid_string_static ( sid ) ,
domain - > name ) ) ;
2002-07-15 14:35:28 +04:00
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = cm_get_lsa_handle ( domain - > name , & hnd ) ) )
return result ;
2001-12-03 14:11:14 +03:00
2003-06-21 08:05:01 +04:00
result = cli_lsa_lookup_sids ( hnd - > cli , mem_ctx , & hnd - > pol ,
2003-02-15 04:34:37 +03:00
1 , sid , & domains , & names , & types ) ;
2003-06-21 08:05:01 +04:00
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & &
hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-03 14:11:14 +03:00
2003-06-21 08:05:01 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
2001-12-03 14:11:14 +03:00
* type = types [ 0 ] ;
* name = names [ 0 ] ;
2002-01-20 04:24:59 +03:00
DEBUG ( 5 , ( " Mapped sid to [%s] \\ [%s] \n " , domains [ 0 ] , * name ) ) ;
2001-12-03 14:11:14 +03:00
2002-03-25 02:25:05 +03:00
/* Paranoia */
2002-01-20 04:24:59 +03:00
if ( strcasecmp ( domain - > name , domains [ 0 ] ) ! = 0 ) {
DEBUG ( 1 , ( " domain name from domain param and PDC lookup return differ! (%s vs %s) \n " , domain - > name , domains [ 0 ] ) ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
}
2003-06-21 08:05:01 +04:00
return result ;
2001-12-03 14:11:14 +03:00
}
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 ,
2003-04-23 15:54:56 +04:00
DOM_SID * user_sid ,
2001-12-04 09:17:39 +03:00
WINBIND_USERINFO * user_info )
{
2003-04-23 15:54:56 +04:00
CLI_POLICY_HND * hnd = NULL ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2001-12-04 09:17:39 +03:00
POLICY_HND dom_pol , user_pol ;
BOOL got_dom_pol = False , got_user_pol = False ;
SAM_USERINFO_CTR * ctr ;
2003-02-15 04:34:37 +03:00
int retry ;
2003-04-23 15:54:56 +04:00
fstring sid_string ;
uint32 user_rid ;
2003-06-21 08:05:01 +04:00
NET_USER_INFO_3 * user ;
2001-12-04 09:17:39 +03:00
2003-04-23 15:54:56 +04:00
DEBUG ( 3 , ( " rpc: query_user rid=%s \n " , sid_to_string ( sid_string , user_sid ) ) ) ;
if ( ! sid_peek_check_rid ( & domain - > sid , user_sid , & user_rid ) ) {
goto done ;
}
2003-06-21 08:05:01 +04:00
/* try netsamlogon cache first */
if ( ( user = netsamlogon_cache_get ( mem_ctx , user_sid ) ) ! = NULL )
{
DEBUG ( 5 , ( " query_user: Cache lookup succeeded for %s \n " ,
sid_string_static ( user_sid ) ) ) ;
user_info - > user_sid = rid_to_talloced_sid ( domain , mem_ctx , user_rid ) ;
user_info - > group_sid = rid_to_talloced_sid ( domain , mem_ctx , user - > group_rid ) ;
user_info - > acct_name = unistr2_tdup ( mem_ctx , & user - > uni_user_name ) ;
user_info - > full_name = unistr2_tdup ( mem_ctx , & user - > uni_full_name ) ;
SAFE_FREE ( user ) ;
return NT_STATUS_OK ;
}
/* no cache; hit the wire */
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
/* Get sam handle; if we fail here there is no hope */
if ( ! NT_STATUS_IS_OK ( result = cm_get_sam_handle ( domain - > name , & hnd ) ) )
2003-02-15 04:34:37 +03:00
goto done ;
2003-06-21 08:05:01 +04:00
2003-02-15 04:34:37 +03:00
/* Get domain handle */
2001-12-04 09:17:39 +03:00
2003-02-15 04:34:37 +03:00
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
SEC_RIGHTS_MAXIMUM_ALLOWED ,
& domain - > sid , & dom_pol ) ;
2003-06-21 08:05:01 +04:00
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & &
hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-04 09:17:39 +03:00
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 ;
2002-04-04 06:39:57 +04:00
got_user_pol = True ;
2001-12-04 09:17:39 +03:00
/* Get user info */
result = cli_samr_query_userinfo ( hnd - > cli , mem_ctx , & user_pol ,
0x15 , & ctr ) ;
2002-07-15 14:35:28 +04:00
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
2001-12-04 09:17:39 +03:00
cli_samr_close ( hnd - > cli , mem_ctx , & user_pol ) ;
2002-04-04 06:39:57 +04:00
got_user_pol = False ;
2001-12-04 09:17:39 +03:00
2003-04-23 15:54:56 +04:00
user_info - > user_sid = rid_to_talloced_sid ( domain , mem_ctx , user_rid ) ;
user_info - > group_sid = rid_to_talloced_sid ( domain , mem_ctx , 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 ,
2003-04-23 15:54:56 +04:00
DOM_SID * user_sid ,
2003-06-21 08:05:01 +04:00
uint32 * num_groups , DOM_SID * * * user_grpsids )
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 ;
2003-04-23 15:54:56 +04:00
unsigned int i ;
unsigned int retry ;
fstring sid_string ;
uint32 user_rid ;
2003-06-21 08:05:01 +04:00
NET_USER_INFO_3 * user ;
2001-12-04 09:46:53 +03:00
2003-04-23 15:54:56 +04:00
DEBUG ( 3 , ( " rpc: lookup_usergroups sid=%s \n " , sid_to_string ( sid_string , user_sid ) ) ) ;
2002-07-15 14:35:28 +04:00
2001-12-11 01:10:16 +03:00
* num_groups = 0 ;
2003-06-21 08:05:01 +04:00
* user_grpsids = NULL ;
2001-12-11 01:10:16 +03:00
2003-06-21 08:05:01 +04:00
/* so lets see if we have a cached user_info_3 */
if ( ( user = netsamlogon_cache_get ( mem_ctx , user_sid ) ) ! = NULL )
{
DEBUG ( 5 , ( " query_user: Cache lookup succeeded for %s \n " ,
sid_string_static ( user_sid ) ) ) ;
* num_groups = user - > num_groups ;
( * user_grpsids ) = talloc ( mem_ctx , sizeof ( DOM_SID * ) * ( * num_groups ) ) ;
for ( i = 0 ; i < ( * num_groups ) ; i + + ) {
( * user_grpsids ) [ i ] = rid_to_talloced_sid ( domain , mem_ctx , user - > gids [ i ] . g_rid ) ;
}
SAFE_FREE ( user ) ;
2002-01-13 02:57:10 +03:00
return NT_STATUS_OK ;
}
2003-06-21 08:05:01 +04:00
/* no cache; hit the wire */
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
/* Get sam handle; if we fail here there is no hope */
if ( ! NT_STATUS_IS_OK ( result = cm_get_sam_handle ( domain - > name , & hnd ) ) )
2003-02-15 04:34:37 +03:00
goto done ;
2001-12-04 09:46:53 +03:00
2003-02-15 04:34:37 +03:00
/* Get domain handle */
2003-06-21 08:05:01 +04:00
2003-02-15 04:34:37 +03:00
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
2003-04-23 15:54:56 +04:00
des_access , & domain - > sid , & dom_pol ) ;
2003-06-21 08:05:01 +04:00
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & &
hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-04 09:46:53 +03:00
if ( ! NT_STATUS_IS_OK ( result ) )
goto done ;
got_dom_pol = True ;
2003-04-23 15:54:56 +04:00
if ( ! sid_peek_check_rid ( & domain - > sid , user_sid , & user_rid ) ) {
goto done ;
}
2001-12-04 09:46:53 +03:00
/* 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 ;
2003-06-21 08:05:01 +04:00
( * user_grpsids ) = talloc ( mem_ctx , sizeof ( DOM_SID * ) * ( * num_groups ) ) ;
if ( ! ( * user_grpsids ) ) {
2003-04-23 15:54:56 +04:00
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2001-12-04 09:46:53 +03:00
for ( i = 0 ; i < ( * num_groups ) ; i + + ) {
2003-06-21 08:05:01 +04:00
( * user_grpsids ) [ i ] = rid_to_talloced_sid ( domain , mem_ctx , user_groups [ i ] . g_rid ) ;
2001-12-04 09:46:53 +03:00
}
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 ,
2003-04-23 15:54:56 +04:00
DOM_SID * group_sid , uint32 * num_names ,
DOM_SID * * * sid_mem , char * * * names ,
2001-12-05 07:48:51 +03:00
uint32 * * name_types )
{
2003-04-23 15:54:56 +04:00
CLI_POLICY_HND * hnd = NULL ;
2001-12-05 07:48:51 +03:00
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 ;
2003-04-23 15:54:56 +04:00
uint32 * rid_mem = NULL ;
uint32 group_rid ;
2003-02-15 04:34:37 +03:00
int retry ;
2003-04-23 15:54:56 +04:00
unsigned int j ;
fstring sid_string ;
2001-12-05 07:48:51 +03:00
2003-04-23 15:54:56 +04:00
DEBUG ( 10 , ( " rpc: lookup_groupmem %s sid=%s \n " , domain - > name , sid_to_string ( sid_string , group_sid ) ) ) ;
if ( ! sid_peek_check_rid ( & domain - > sid , group_sid , & group_rid ) ) {
goto done ;
}
2002-07-15 14:35:28 +04:00
2001-12-11 01:10:16 +03:00
* num_names = 0 ;
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
/* Get sam handle */
2003-06-21 08:05:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = cm_get_sam_handle ( domain - > name , & hnd ) ) )
2003-02-15 04:34:37 +03:00
goto done ;
2001-12-05 07:48:51 +03:00
2003-02-15 04:34:37 +03:00
/* Get domain handle */
2001-12-05 07:48:51 +03:00
2003-02-15 04:34:37 +03:00
result = cli_samr_open_domain ( hnd - > cli , mem_ctx , & hnd - > pol ,
des_access , & domain - > sid , & dom_pol ) ;
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & & hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-05 07:48:51 +03:00
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 ,
2003-04-23 15:54:56 +04:00
& group_pol , num_names , & rid_mem ,
2001-12-05 07:48:51 +03:00
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
2002-04-11 18:30:31 +04:00
* names = talloc_zero ( mem_ctx , * num_names * sizeof ( char * ) ) ;
* name_types = talloc_zero ( mem_ctx , * num_names * sizeof ( uint32 ) ) ;
2003-04-23 15:54:56 +04:00
* sid_mem = talloc_zero ( mem_ctx , * num_names * sizeof ( DOM_SID * ) ) ;
for ( j = 0 ; j < ( * num_names ) ; j + + ) {
( * sid_mem ) [ j ] = rid_to_talloced_sid ( domain , mem_ctx , ( rid_mem ) [ j ] ) ;
}
if ( ! * names | | ! * name_types ) {
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2001-12-05 07:48:51 +03:00
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 ,
2003-04-23 15:54:56 +04:00
& rid_mem [ i ] ,
2001-12-05 07:48:51 +03:00
& tmp_num_names ,
& tmp_names , & tmp_types ) ;
2003-06-21 08:05:01 +04:00
/* see if we have a real error (and yes the STATUS_SOME_UNMAPPED is
the one returned from 2 k ) */
if ( ! NT_STATUS_IS_OK ( result ) & & NT_STATUS_V ( result ) ! = NT_STATUS_V ( STATUS_SOME_UNMAPPED ) )
2001-12-05 07:48:51 +03:00
goto done ;
2003-06-21 08:05:01 +04:00
2001-12-05 07:48:51 +03:00
/* 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 ) ;
2003-04-23 15:54:56 +04:00
2001-12-05 07:48:51 +03:00
total_names + = tmp_num_names ;
}
* num_names = total_names ;
2003-06-21 08:05:01 +04:00
result = NT_STATUS_OK ;
done :
2001-12-05 07:48:51 +03:00
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 ;
}
2003-06-23 09:10:07 +04:00
# ifdef HAVE_LDAP
# include <ldap.h>
static SIG_ATOMIC_T gotalarm ;
/***************************************************************
Signal function to tell us we timed out .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void gotalarm_sig ( void )
{
gotalarm = 1 ;
}
static LDAP * ldap_open_with_timeout ( const char * server , int port , unsigned int to )
{
LDAP * ldp = NULL ;
/* Setup timeout */
gotalarm = 0 ;
CatchSignal ( SIGALRM , SIGNAL_CAST gotalarm_sig ) ;
alarm ( to ) ;
/* End setup timeout. */
ldp = ldap_open ( server , port ) ;
/* Teardown timeout. */
CatchSignal ( SIGALRM , SIGNAL_CAST SIG_IGN ) ;
alarm ( 0 ) ;
return ldp ;
}
static int get_ldap_seq ( const char * server , uint32 * seq )
{
int ret = - 1 ;
struct timeval to ;
char * attrs [ ] = { " highestCommittedUSN " , NULL } ;
LDAPMessage * res = NULL ;
char * * values = NULL ;
LDAP * ldp = NULL ;
* seq = DOM_SEQUENCE_NONE ;
/*
* 10 second timeout on open . This is needed as the search timeout
* doesn ' t seem to apply to doing an open as well . JRA .
*/
if ( ( ldp = ldap_open_with_timeout ( server , LDAP_PORT , 10 ) ) = = NULL )
return - 1 ;
/* Timeout if no response within 20 seconds. */
to . tv_sec = 10 ;
to . tv_usec = 0 ;
if ( ldap_search_st ( ldp , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , & attrs [ 0 ] , 0 , & to , & res ) )
goto done ;
if ( ldap_count_entries ( ldp , res ) ! = 1 )
goto done ;
values = ldap_get_values ( ldp , res , " highestCommittedUSN " ) ;
if ( ! values | | ! values [ 0 ] )
goto done ;
* seq = atoi ( values [ 0 ] ) ;
ret = 0 ;
done :
if ( values )
ldap_value_free ( values ) ;
if ( res )
ldap_msgfree ( res ) ;
if ( ldp )
ldap_unbind ( ldp ) ;
return ret ;
}
/**********************************************************************
Get the sequence number for a Windows AD native mode domain using
LDAP queries
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int get_ldap_sequence_number ( const char * domain , uint32 * seq )
{
int ret = - 1 ;
int i ;
struct in_addr * ip_list = NULL ;
int count ;
BOOL list_ordered ;
if ( ! get_dc_list ( domain , & ip_list , & count , & list_ordered ) ) {
DEBUG ( 3 , ( " Could not look up dc's for domain %s \n " , domain ) ) ;
return False ;
}
2003-06-23 23:05:23 +04:00
/* sort the list so we can pick a close server */
2003-06-23 09:10:07 +04:00
2003-06-23 23:05:23 +04:00
if ( ! list_ordered & & ( count > 1 ) ) {
qsort ( ip_list , count , sizeof ( struct in_addr ) , QSORT_CAST ip_compare ) ;
2003-06-23 09:10:07 +04:00
}
/* Finally return first DC that we can contact */
for ( i = 0 ; i < count ; i + + ) {
if ( is_zero_ip ( ip_list [ i ] ) )
continue ;
if ( ( ret = get_ldap_seq ( inet_ntoa ( ip_list [ i ] ) , seq ) ) = = 0 )
goto done ;
}
done :
if ( ret = = 0 ) {
DEBUG ( 3 , ( " get_ldap_sequence_number: Retrieved sequence number for Domain (%s) from DC (%s) \n " ,
domain , inet_ntoa ( ip_list [ i ] ) ) ) ;
}
SAFE_FREE ( ip_list ) ;
return ret ;
}
# endif /* HAVE_LDAP */
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 ;
POLICY_HND dom_pol ;
BOOL got_dom_pol = False ;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED ;
2003-02-15 04:34:37 +03:00
int retry ;
2001-12-05 10:52:44 +03:00
2002-09-25 19:19:00 +04:00
DEBUG ( 10 , ( " rpc: fetch sequence_number for %s \n " , domain - > name ) ) ;
2002-07-15 14:35:28 +04:00
2001-12-10 02:59:42 +03:00
* seq = DOM_SEQUENCE_NONE ;
2002-12-20 23:21:31 +03:00
if ( ! ( mem_ctx = talloc_init ( " sequence_number[rpc] " ) ) )
2001-12-10 02:59:42 +03:00
return NT_STATUS_NO_MEMORY ;
2001-12-05 10:52:44 +03:00
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-23 09:10:07 +04:00
# ifdef HAVE_LDAP
if ( domain - > native_mode )
{
DEBUG ( 8 , ( " using get_ldap_seq() to retrieve the sequence number \n " ) ) ;
if ( get_ldap_sequence_number ( domain - > name , seq ) = = 0 ) {
result = NT_STATUS_OK ;
DEBUG ( 10 , ( " domain_sequence_number: LDAP for domain %s is %u \n " ,
domain - > name , * seq ) ) ;
goto done ;
}
DEBUG ( 10 , ( " domain_sequence_number: failed to get LDAP sequence number for domain %s \n " ,
domain - > name ) ) ;
}
# endif /* HAVE_LDAP */
2003-06-21 08:05:01 +04:00
/* Get sam handle */
if ( ! NT_STATUS_IS_OK ( result = cm_get_sam_handle ( domain - > name , & hnd ) ) )
2003-02-15 04:34:37 +03:00
goto done ;
2001-12-05 10:52:44 +03:00
2003-02-15 04:34:37 +03:00
/* 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 ) ;
2003-02-15 04:34:37 +03:00
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & & hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
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 ) ) {
2003-06-25 03:07:26 +04:00
* seq = ctr . info . inf2 . seq_num ;
DEBUG ( 10 , ( " domain_sequence_number: for domain %s is %u \n " , domain - > name , ( unsigned ) * seq ) ) ;
2001-12-05 10:52:44 +03:00
} else {
DEBUG ( 10 , ( " domain_sequence_number: failed to get sequence number (%u) for domain %s \n " ,
2003-06-25 03:07:26 +04:00
( unsigned ) * seq , domain - > name ) ) ;
2001-12-05 10:52:44 +03:00
}
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
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 ,
2002-08-17 21:00:51 +04:00
char * * * alt_names ,
2001-12-10 05:25:19 +03:00
DOM_SID * * dom_sids )
{
CLI_POLICY_HND * hnd ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
uint32 enum_ctx = 0 ;
2003-02-15 04:34:37 +03:00
int retry ;
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " rpc: trusted_domains \n " ) ) ;
2001-12-10 05:25:19 +03:00
2001-12-11 01:10:16 +03:00
* num_domains = 0 ;
2002-08-17 21:00:51 +04:00
* alt_names = NULL ;
2001-12-11 01:10:16 +03:00
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = cm_get_lsa_handle ( lp_workgroup ( ) , & hnd ) ) )
2003-02-15 04:34:37 +03:00
goto done ;
result = cli_lsa_enum_trust_dom ( hnd - > cli , mem_ctx ,
& hnd - > pol , & enum_ctx ,
num_domains , names , dom_sids ) ;
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & & hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-10 05:25:19 +03:00
done :
return result ;
}
/* find the domain sid for a domain */
static NTSTATUS domain_sid ( struct winbindd_domain * domain , DOM_SID * sid )
{
2003-06-21 08:05:01 +04:00
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2001-12-10 05:25:19 +03:00
TALLOC_CTX * mem_ctx ;
CLI_POLICY_HND * hnd ;
fstring level5_dom ;
2003-02-15 04:34:37 +03:00
int retry ;
2001-12-10 05:25:19 +03:00
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " rpc: domain_sid \n " ) ) ;
2002-12-20 23:21:31 +03:00
if ( ! ( mem_ctx = talloc_init ( " domain_sid[rpc] " ) ) )
2001-12-10 05:25:19 +03:00
return NT_STATUS_NO_MEMORY ;
2003-02-15 04:34:37 +03:00
retry = 0 ;
do {
2003-06-21 08:05:01 +04:00
/* Get lsa handle */
if ( ! NT_STATUS_IS_OK ( result = cm_get_lsa_handle ( domain - > name , & hnd ) ) )
2003-02-15 04:34:37 +03:00
goto done ;
2001-12-10 05:25:19 +03:00
2003-06-21 08:05:01 +04:00
result = cli_lsa_query_info_policy ( hnd - > cli , mem_ctx ,
2001-12-10 05:25:19 +03:00
& hnd - > pol , 0x05 , level5_dom , sid ) ;
2003-06-21 08:05:01 +04:00
} while ( ! NT_STATUS_IS_OK ( result ) & & ( retry + + < 1 ) & & hnd & & hnd - > cli & & hnd - > cli - > fd = = - 1 ) ;
2001-12-10 05:25:19 +03:00
done :
talloc_destroy ( mem_ctx ) ;
2003-06-21 08:05:01 +04:00
return result ;
2001-12-10 05:25:19 +03:00
}
2001-12-05 07:48:51 +03:00
2002-08-17 21:00:51 +04:00
/* find alternate names list for the domain - none for rpc */
static NTSTATUS alternate_name ( struct winbindd_domain * domain )
{
return NT_STATUS_OK ;
}
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 ,
2002-10-08 22:32:42 +04:00
enum_local_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 ,
2002-08-17 21:00:51 +04:00
domain_sid ,
alternate_name
2001-12-03 04:23:42 +03:00
} ;