2003-08-28 00:52:56 +04:00
/*
Unix SMB / CIFS implementation .
uid / user handling
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) Gerald ( Jerry ) Carter 2003
2006-02-04 01:19:41 +03:00
Copyright ( C ) Volker Lendecke 2005
2003-08-28 00:52:56 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-28 00:52:56 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-28 00:52:56 +04:00
*/
# include "includes.h"
2010-05-28 04:19:32 +04:00
# include "../librpc/gen_ndr/ndr_security.h"
2003-08-28 00:52:56 +04:00
/*****************************************************************
2005-12-03 21:34:13 +03:00
Dissect a user - provided name into domain , name , sid and type .
If an explicit domain name was given in the form domain \ user , it
has to try that . If no explicit domain name was given , we have
to do guesswork .
2003-08-28 00:52:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool lookup_name ( TALLOC_CTX * mem_ctx ,
2005-12-03 21:34:13 +03:00
const char * full_name , int flags ,
2005-12-10 14:22:01 +03:00
const char * * ret_domain , const char * * ret_name ,
2010-05-21 05:25:01 +04:00
struct dom_sid * ret_sid , enum lsa_SidType * ret_type )
2003-08-28 00:52:56 +04:00
{
2005-12-10 14:22:01 +03:00
char * p ;
2008-09-03 22:36:43 +04:00
const char * tmp ;
const char * domain = NULL ;
const char * name = NULL ;
uint32 rid ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2008-09-03 22:36:43 +04:00
enum lsa_SidType type ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
if ( tmp_ctx = = NULL ) {
DEBUG ( 0 , ( " talloc_new failed \n " ) ) ;
return false ;
}
2005-12-03 21:34:13 +03:00
p = strchr_m ( full_name , ' \\ ' ) ;
if ( p ! = NULL ) {
2008-09-03 22:36:43 +04:00
domain = talloc_strndup ( tmp_ctx , full_name ,
2005-12-03 21:34:13 +03:00
PTR_DIFF ( p , full_name ) ) ;
2008-09-03 22:36:43 +04:00
name = talloc_strdup ( tmp_ctx , p + 1 ) ;
2005-12-03 21:34:13 +03:00
} else {
2008-09-03 22:36:43 +04:00
domain = talloc_strdup ( tmp_ctx , " " ) ;
name = talloc_strdup ( tmp_ctx , full_name ) ;
2005-12-03 21:34:13 +03:00
}
2008-09-03 22:36:43 +04:00
if ( ( domain = = NULL ) | | ( name = = NULL ) ) {
2005-12-03 21:34:13 +03:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2008-09-03 22:36:43 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
2003-08-28 00:52:56 +04:00
2010-04-28 12:54:57 +04:00
DEBUG ( 10 , ( " lookup_name: %s => domain=[%s], name=[%s] \n " ,
2008-09-03 22:36:43 +04:00
full_name , domain , name ) ) ;
2007-12-12 20:03:20 +03:00
DEBUG ( 10 , ( " lookup_name: flags = 0x0%x \n " , flags ) ) ;
if ( ( flags & LOOKUP_NAME_DOMAIN ) & &
strequal ( domain , get_global_sam_name ( ) ) )
{
2005-12-03 21:34:13 +03:00
/* It's our own domain, lookup the name in passdb */
2006-02-04 01:19:41 +03:00
if ( lookup_global_sam_name ( name , flags , & rid , & type ) ) {
2010-01-10 19:39:27 +03:00
sid_compose ( & sid , get_global_sam_sid ( ) , rid ) ;
2005-12-03 21:34:13 +03:00
goto ok ;
2003-08-28 00:52:56 +04:00
}
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
2007-12-12 20:03:20 +03:00
if ( ( flags & LOOKUP_NAME_BUILTIN ) & &
strequal ( domain , builtin_domain_name ( ) ) )
{
2009-10-20 17:13:56 +04:00
if ( strlen ( name ) = = 0 ) {
/* Swap domain and name */
tmp = name ; name = domain ; domain = tmp ;
sid_copy ( & sid , & global_sid_Builtin ) ;
type = SID_NAME_DOMAIN ;
goto ok ;
}
2005-12-03 21:34:13 +03:00
/* Explicit request for a name in BUILTIN */
if ( lookup_builtin_name ( name , & rid ) ) {
2010-01-10 19:39:27 +03:00
sid_compose ( & sid , & global_sid_Builtin , rid ) ;
2005-12-03 21:34:13 +03:00
type = SID_NAME_ALIAS ;
goto ok ;
2003-08-28 00:52:56 +04:00
}
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2003-08-28 00:52:56 +04:00
}
2005-12-03 21:34:13 +03:00
2006-02-04 01:19:41 +03:00
/* Try the explicit winbind lookup first, don't let it guess the
2008-09-03 22:36:43 +04:00
* domain yet at this point yet . This comes later . */
2006-02-04 01:19:41 +03:00
if ( ( domain [ 0 ] ! = ' \0 ' ) & &
2007-12-12 20:03:20 +03:00
( flags & ~ ( LOOKUP_NAME_DOMAIN | LOOKUP_NAME_ISOLATED ) ) & &
2006-02-04 01:19:41 +03:00
( winbind_lookup_name ( domain , name , & sid , & type ) ) ) {
goto ok ;
}
2009-08-01 01:17:54 +04:00
if ( ( ( flags & LOOKUP_NAME_NO_NSS ) = = 0 )
& & strequal ( domain , unix_users_domain_name ( ) ) ) {
2006-02-04 01:19:41 +03:00
if ( lookup_unix_user_name ( name , & sid ) ) {
type = SID_NAME_USER ;
goto ok ;
}
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
2009-08-01 01:17:54 +04:00
if ( ( ( flags & LOOKUP_NAME_NO_NSS ) = = 0 )
& & strequal ( domain , unix_groups_domain_name ( ) ) ) {
2006-02-04 01:19:41 +03:00
if ( lookup_unix_group_name ( name , & sid ) ) {
type = SID_NAME_DOM_GRP ;
2005-12-03 21:34:13 +03:00
goto ok ;
}
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
2006-02-04 01:19:41 +03:00
if ( ( domain [ 0 ] = = ' \0 ' ) & & ( ! ( flags & LOOKUP_NAME_ISOLATED ) ) ) {
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
/* Now the guesswork begins, we haven't been given an explicit
* domain . Try the sequence as documented on
* http : //msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
* November 27 , 2005 */
/* 1. well-known names */
2007-12-12 20:03:20 +03:00
if ( ( flags & LOOKUP_NAME_WKN ) & &
2008-09-03 22:36:43 +04:00
lookup_wellknown_name ( tmp_ctx , name , & sid , & domain ) )
2007-12-12 20:03:20 +03:00
{
2006-02-24 23:50:13 +03:00
type = SID_NAME_WKN_GRP ;
goto ok ;
2005-12-03 21:34:13 +03:00
}
/* 2. Builtin domain as such */
2007-12-12 20:03:20 +03:00
if ( ( flags & ( LOOKUP_NAME_BUILTIN | LOOKUP_NAME_REMOTE ) ) & &
strequal ( name , builtin_domain_name ( ) ) )
{
2005-12-03 21:34:13 +03:00
/* Swap domain and name */
tmp = name ; name = domain ; domain = tmp ;
sid_copy ( & sid , & global_sid_Builtin ) ;
type = SID_NAME_DOMAIN ;
goto ok ;
}
/* 3. Account domain */
2007-12-12 20:03:20 +03:00
if ( ( flags & LOOKUP_NAME_DOMAIN ) & &
strequal ( name , get_global_sam_name ( ) ) )
{
2005-12-03 21:34:13 +03:00
if ( ! secrets_fetch_domain_sid ( name , & sid ) ) {
DEBUG ( 3 , ( " Could not fetch my SID \n " ) ) ;
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
/* Swap domain and name */
tmp = name ; name = domain ; domain = tmp ;
type = SID_NAME_DOMAIN ;
goto ok ;
}
/* 4. Primary domain */
2007-12-12 20:03:20 +03:00
if ( ( flags & LOOKUP_NAME_DOMAIN ) & & ! IS_DC & &
strequal ( name , lp_workgroup ( ) ) )
{
2005-12-03 21:34:13 +03:00
if ( ! secrets_fetch_domain_sid ( name , & sid ) ) {
DEBUG ( 3 , ( " Could not fetch the domain SID \n " ) ) ;
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
/* Swap domain and name */
tmp = name ; name = domain ; domain = tmp ;
type = SID_NAME_DOMAIN ;
goto ok ;
}
/* 5. Trusted domains as such, to me it looks as if members don't do
this , tested an XP workstation in a NT domain - - vl */
2007-12-12 20:03:20 +03:00
if ( ( flags & LOOKUP_NAME_REMOTE ) & & IS_DC & &
2007-12-17 16:51:37 +03:00
( pdb_get_trusteddom_pw ( name , NULL , & sid , NULL ) ) )
2007-12-12 20:03:20 +03:00
{
2005-12-03 21:34:13 +03:00
/* Swap domain and name */
tmp = name ; name = domain ; domain = tmp ;
type = SID_NAME_DOMAIN ;
goto ok ;
}
2008-09-03 22:36:43 +04:00
/* 6. Builtin aliases */
2005-12-03 21:34:13 +03:00
2007-12-12 20:03:20 +03:00
if ( ( flags & LOOKUP_NAME_BUILTIN ) & &
lookup_builtin_name ( name , & rid ) )
{
2008-09-03 22:36:43 +04:00
domain = talloc_strdup ( tmp_ctx , builtin_domain_name ( ) ) ;
2010-01-10 19:39:27 +03:00
sid_compose ( & sid , & global_sid_Builtin , rid ) ;
2005-12-03 21:34:13 +03:00
type = SID_NAME_ALIAS ;
goto ok ;
}
/* 7. Local systems' SAM (DCs don't have a local SAM) */
/* 8. Primary SAM (On members, this is the domain) */
/* Both cases are done by looking at our passdb */
2007-12-12 20:03:20 +03:00
if ( ( flags & LOOKUP_NAME_DOMAIN ) & &
lookup_global_sam_name ( name , flags , & rid , & type ) )
{
2008-09-03 22:36:43 +04:00
domain = talloc_strdup ( tmp_ctx , get_global_sam_name ( ) ) ;
2010-01-10 19:39:27 +03:00
sid_compose ( & sid , get_global_sam_sid ( ) , rid ) ;
2005-12-03 21:34:13 +03:00
goto ok ;
}
/* Now our local possibilities are exhausted. */
if ( ! ( flags & LOOKUP_NAME_REMOTE ) ) {
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
/* If we are not a DC, we have to ask in our primary domain. Let
* winbind do that . */
if ( ! IS_DC & &
( winbind_lookup_name ( lp_workgroup ( ) , name , & sid , & type ) ) ) {
2008-09-03 22:36:43 +04:00
domain = talloc_strdup ( tmp_ctx , lp_workgroup ( ) ) ;
2005-12-03 21:34:13 +03:00
goto ok ;
}
/* 9. Trusted domains */
/* If we're a DC we have to ask all trusted DC's. Winbind does not do
* that ( yet ) , but give it a chance . */
if ( IS_DC & & winbind_lookup_name ( " " , name , & sid , & type ) ) {
2010-05-21 05:25:01 +04:00
struct dom_sid dom_sid ;
2005-12-03 21:34:13 +03:00
uint32 tmp_rid ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType domain_type ;
2008-09-03 22:36:43 +04:00
2005-12-03 21:34:13 +03:00
if ( type = = SID_NAME_DOMAIN ) {
/* Swap name and type */
tmp = name ; name = domain ; domain = tmp ;
goto ok ;
}
/* Here we have to cope with a little deficiency in the
* winbind API : We have to ask it again for the name of the
* domain it figured out itself . Maybe fix that later . . . */
sid_copy ( & dom_sid , & sid ) ;
sid_split_rid ( & dom_sid , & tmp_rid ) ;
2005-12-10 14:22:01 +03:00
if ( ! winbind_lookup_sid ( tmp_ctx , & dom_sid , & domain , NULL ,
2005-12-03 21:34:13 +03:00
& domain_type ) | |
( domain_type ! = SID_NAME_DOMAIN ) ) {
2005-12-10 14:22:01 +03:00
DEBUG ( 2 , ( " winbind could not find the domain's name "
" it just looked up for us \n " ) ) ;
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
goto ok ;
}
/* 10. Don't translate */
2006-02-04 01:19:41 +03:00
/* 11. Ok, windows would end here. Samba has two more options:
Unmapped users and unmapped groups */
2009-08-01 01:17:54 +04:00
if ( ( ( flags & LOOKUP_NAME_NO_NSS ) = = 0 )
& & lookup_unix_user_name ( name , & sid ) ) {
2008-09-03 22:36:43 +04:00
domain = talloc_strdup ( tmp_ctx , unix_users_domain_name ( ) ) ;
2006-02-04 01:19:41 +03:00
type = SID_NAME_USER ;
goto ok ;
}
2009-08-01 01:17:54 +04:00
if ( ( ( flags & LOOKUP_NAME_NO_NSS ) = = 0 )
& & lookup_unix_group_name ( name , & sid ) ) {
2008-09-03 22:36:43 +04:00
domain = talloc_strdup ( tmp_ctx , unix_groups_domain_name ( ) ) ;
2006-02-04 01:19:41 +03:00
type = SID_NAME_DOM_GRP ;
goto ok ;
}
2006-07-11 22:01:26 +04:00
/*
* Ok , all possibilities tried . Fail .
*/
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
ok :
2008-09-03 22:36:43 +04:00
if ( ( domain = = NULL ) | | ( name = = NULL ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
return false ;
}
2006-07-11 22:01:26 +04:00
/*
* Hand over the results to the talloc context we ' ve been given .
*/
if ( ( ret_name ! = NULL ) & &
! ( * ret_name = talloc_strdup ( mem_ctx , name ) ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
if ( ret_domain ! = NULL ) {
2006-07-11 22:01:26 +04:00
char * tmp_dom ;
2008-09-03 22:36:43 +04:00
if ( ! ( tmp_dom = talloc_strdup ( mem_ctx , domain ) ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
return false ;
2006-07-11 22:01:26 +04:00
}
2005-12-10 14:22:01 +03:00
strupper_m ( tmp_dom ) ;
2006-07-11 22:01:26 +04:00
* ret_domain = tmp_dom ;
2005-12-03 21:34:13 +03:00
}
if ( ret_sid ! = NULL ) {
sid_copy ( ret_sid , & sid ) ;
}
if ( ret_type ! = NULL ) {
* ret_type = type ;
}
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return true ;
2003-08-28 00:52:56 +04:00
}
2006-08-05 00:35:52 +04:00
/************************************************************************
Names from smb . conf can be unqualified . eg . valid users = foo
2006-08-05 00:43:21 +04:00
These names should never map to a remote name . Try global_sam_name ( ) \ foo ,
2006-08-05 00:35:52 +04:00
and then " Unix Users " \ foo ( or " Unix Groups " \ foo ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool lookup_name_smbconf ( TALLOC_CTX * mem_ctx ,
2006-08-05 00:35:52 +04:00
const char * full_name , int flags ,
const char * * ret_domain , const char * * ret_name ,
2010-05-21 05:25:01 +04:00
struct dom_sid * ret_sid , enum lsa_SidType * ret_type )
2006-08-05 00:35:52 +04:00
{
2008-09-03 22:36:43 +04:00
char * qualified_name ;
const char * p ;
2006-08-05 01:07:32 +04:00
2008-09-03 22:36:43 +04:00
/* NB. No winbindd_separator here as lookup_name needs \\' */
if ( ( p = strchr_m ( full_name , * lp_winbind_separator ( ) ) ) ! = NULL ) {
2006-08-05 01:07:32 +04:00
2008-09-03 22:36:43 +04:00
/* The name is already qualified with a domain. */
if ( * lp_winbind_separator ( ) ! = ' \\ ' ) {
char * tmp ;
/* lookup_name() needs '\\' as a separator */
tmp = talloc_strdup ( mem_ctx , full_name ) ;
if ( ! tmp ) {
return false ;
}
tmp [ p - full_name ] = ' \\ ' ;
full_name = tmp ;
2006-08-05 01:07:32 +04:00
}
2008-09-03 22:36:43 +04:00
return lookup_name ( mem_ctx , full_name , flags ,
ret_domain , ret_name ,
ret_sid , ret_type ) ;
2006-08-05 00:35:52 +04:00
}
2006-08-05 00:43:21 +04:00
/* Try with our own SAM name. */
2008-09-03 22:36:43 +04:00
qualified_name = talloc_asprintf ( mem_ctx , " %s \\ %s " ,
get_global_sam_name ( ) ,
full_name ) ;
if ( ! qualified_name ) {
return false ;
2006-08-05 00:35:52 +04:00
}
2008-08-18 03:54:41 +04:00
2008-09-03 22:36:43 +04:00
if ( lookup_name ( mem_ctx , qualified_name , flags ,
ret_domain , ret_name ,
ret_sid , ret_type ) ) {
return true ;
}
2006-08-05 00:35:52 +04:00
/* Finally try with "Unix Users" or "Unix Group" */
2008-09-03 22:36:43 +04:00
qualified_name = talloc_asprintf ( mem_ctx , " %s \\ %s " ,
2006-08-05 00:35:52 +04:00
flags & LOOKUP_NAME_GROUP ?
unix_groups_domain_name ( ) :
unix_users_domain_name ( ) ,
2008-09-03 22:36:43 +04:00
full_name ) ;
if ( ! qualified_name ) {
return false ;
}
2006-08-05 00:35:52 +04:00
2008-09-03 22:36:43 +04:00
return lookup_name ( mem_ctx , qualified_name , flags ,
ret_domain , ret_name ,
ret_sid , ret_type ) ;
2006-08-05 00:35:52 +04:00
}
2007-10-19 04:40:25 +04:00
static bool wb_lookup_rids ( TALLOC_CTX * mem_ctx ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * domain_sid ,
2006-07-11 22:01:26 +04:00
int num_rids , uint32 * rids ,
const char * * domain_name ,
2006-09-08 18:28:06 +04:00
const char * * names , enum lsa_SidType * types )
2006-02-04 01:19:41 +03:00
{
int i ;
2006-07-11 22:01:26 +04:00
const char * * my_names ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType * my_types ;
2006-07-11 22:01:26 +04:00
TALLOC_CTX * tmp_ctx ;
2006-02-04 01:19:41 +03:00
2006-07-11 22:01:26 +04:00
if ( ! ( tmp_ctx = talloc_init ( " wb_lookup_rids " ) ) ) {
2007-11-27 18:36:06 +03:00
return false ;
2006-07-11 22:01:26 +04:00
}
2006-02-04 01:19:41 +03:00
2006-07-11 22:01:26 +04:00
if ( ! winbind_lookup_rids ( tmp_ctx , domain_sid , num_rids , rids ,
domain_name , & my_names , & my_types ) ) {
2006-11-29 11:11:33 +03:00
* domain_name = " " ;
2006-07-11 22:01:26 +04:00
for ( i = 0 ; i < num_rids ; i + + ) {
2006-11-29 11:11:33 +03:00
names [ i ] = " " ;
2006-02-04 01:19:41 +03:00
types [ i ] = SID_NAME_UNKNOWN ;
}
2007-03-10 21:04:47 +03:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return true ;
2006-07-11 22:01:26 +04:00
}
2007-03-16 16:09:09 +03:00
if ( ! ( * domain_name = talloc_strdup ( mem_ctx , * domain_name ) ) ) {
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2007-03-16 16:09:09 +03:00
}
2006-07-11 22:01:26 +04:00
/*
* winbind_lookup_rids allocates its own array . We ' ve been given the
* array , so copy it over
*/
for ( i = 0 ; i < num_rids ; i + + ) {
if ( my_names [ i ] = = NULL ) {
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2006-07-11 22:01:26 +04:00
}
if ( ! ( names [ i ] = talloc_strdup ( names , my_names [ i ] ) ) ) {
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return false ;
2006-07-11 22:01:26 +04:00
}
types [ i ] = my_types [ i ] ;
2006-02-04 01:19:41 +03:00
}
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
2003-08-28 00:52:56 +04:00
2010-05-21 05:25:01 +04:00
static bool lookup_rids ( TALLOC_CTX * mem_ctx , const struct dom_sid * domain_sid ,
2006-02-04 01:19:41 +03:00
int num_rids , uint32_t * rids ,
const char * * domain_name ,
2006-09-08 18:28:06 +04:00
const char * * * names , enum lsa_SidType * * types )
2003-08-28 00:52:56 +04:00
{
2006-02-04 01:19:41 +03:00
int i ;
2005-12-10 14:22:01 +03:00
2008-01-25 01:44:05 +03:00
DEBUG ( 10 , ( " lookup_rids called for domain sid '%s' \n " ,
sid_string_dbg ( domain_sid ) ) ) ;
2007-04-30 06:39:34 +04:00
if ( num_rids ) {
2009-05-06 02:07:40 +04:00
* names = TALLOC_ZERO_ARRAY ( mem_ctx , const char * , num_rids ) ;
2007-04-30 06:39:34 +04:00
* types = TALLOC_ARRAY ( mem_ctx , enum lsa_SidType , num_rids ) ;
2003-08-28 00:52:56 +04:00
2007-04-30 06:39:34 +04:00
if ( ( * names = = NULL ) | | ( * types = = NULL ) ) {
2007-11-27 18:36:06 +03:00
return false ;
2007-04-30 06:39:34 +04:00
}
2009-05-06 02:07:40 +04:00
for ( i = 0 ; i < num_rids ; i + + )
( * types ) [ i ] = SID_NAME_UNKNOWN ;
2007-04-30 06:39:34 +04:00
} else {
* names = NULL ;
* types = NULL ;
2005-12-10 14:22:01 +03:00
}
2006-02-04 01:19:41 +03:00
if ( sid_check_is_domain ( domain_sid ) ) {
NTSTATUS result ;
if ( * domain_name = = NULL ) {
* domain_name = talloc_strdup (
mem_ctx , get_global_sam_name ( ) ) ;
}
if ( * domain_name = = NULL ) {
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
2007-04-06 03:56:10 +04:00
become_root ( ) ;
2006-02-04 01:19:41 +03:00
result = pdb_lookup_rids ( domain_sid , num_rids , rids ,
* names , * types ) ;
2007-04-06 03:56:10 +04:00
unbecome_root ( ) ;
2006-02-04 01:19:41 +03:00
return ( NT_STATUS_IS_OK ( result ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_NONE_MAPPED ) | |
NT_STATUS_EQUAL ( result , STATUS_SOME_UNMAPPED ) ) ;
2004-11-19 16:26:17 +03:00
}
2006-02-04 01:19:41 +03:00
if ( sid_check_is_builtin ( domain_sid ) ) {
2005-11-27 00:02:48 +03:00
2006-02-04 01:19:41 +03:00
if ( * domain_name = = NULL ) {
* domain_name = talloc_strdup (
mem_ctx , builtin_domain_name ( ) ) ;
2005-12-03 21:34:13 +03:00
}
2006-02-04 01:19:41 +03:00
if ( * domain_name = = NULL ) {
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
for ( i = 0 ; i < num_rids ; i + + ) {
if ( lookup_builtin_rid ( * names , rids [ i ] ,
& ( * names ) [ i ] ) ) {
if ( ( * names ) [ i ] = = NULL ) {
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
( * types ) [ i ] = SID_NAME_ALIAS ;
} else {
( * types ) [ i ] = SID_NAME_UNKNOWN ;
}
}
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
if ( sid_check_is_wellknown_domain ( domain_sid , NULL ) ) {
for ( i = 0 ; i < num_rids ; i + + ) {
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2010-01-10 19:39:27 +03:00
sid_compose ( & sid , domain_sid , rids [ i ] ) ;
2006-02-04 01:19:41 +03:00
if ( lookup_wellknown_sid ( mem_ctx , & sid ,
domain_name , & ( * names ) [ i ] ) ) {
if ( ( * names ) [ i ] = = NULL ) {
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
( * types ) [ i ] = SID_NAME_WKN_GRP ;
} else {
( * types ) [ i ] = SID_NAME_UNKNOWN ;
}
}
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
if ( sid_check_is_unix_users ( domain_sid ) ) {
if ( * domain_name = = NULL ) {
* domain_name = talloc_strdup (
mem_ctx , unix_users_domain_name ( ) ) ;
2008-02-06 05:05:59 +03:00
if ( * domain_name = = NULL ) {
return false ;
}
2006-02-04 01:19:41 +03:00
}
for ( i = 0 ; i < num_rids ; i + + ) {
( * names ) [ i ] = talloc_strdup (
( * names ) , uidtoname ( rids [ i ] ) ) ;
2008-02-06 05:05:59 +03:00
if ( ( * names ) [ i ] = = NULL ) {
return false ;
}
2006-02-04 01:19:41 +03:00
( * types ) [ i ] = SID_NAME_USER ;
}
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
if ( sid_check_is_unix_groups ( domain_sid ) ) {
if ( * domain_name = = NULL ) {
* domain_name = talloc_strdup (
mem_ctx , unix_groups_domain_name ( ) ) ;
2008-02-06 05:05:59 +03:00
if ( * domain_name = = NULL ) {
return false ;
}
2006-02-04 01:19:41 +03:00
}
for ( i = 0 ; i < num_rids ; i + + ) {
( * names ) [ i ] = talloc_strdup (
( * names ) , gidtoname ( rids [ i ] ) ) ;
2008-02-06 05:05:59 +03:00
if ( ( * names ) [ i ] = = NULL ) {
return false ;
}
2006-02-04 01:19:41 +03:00
( * types ) [ i ] = SID_NAME_DOM_GRP ;
}
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
2006-07-11 22:01:26 +04:00
return wb_lookup_rids ( mem_ctx , domain_sid , num_rids , rids ,
domain_name , * names , * types ) ;
2006-02-04 01:19:41 +03:00
}
/*
* Is the SID a domain as such ? If yes , lookup its name .
*/
2010-05-21 05:25:01 +04:00
static bool lookup_as_domain ( const struct dom_sid * sid , TALLOC_CTX * mem_ctx ,
2006-02-04 01:19:41 +03:00
const char * * name )
{
const char * tmp ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType type ;
2006-02-04 01:19:41 +03:00
if ( sid_check_is_domain ( sid ) ) {
* name = talloc_strdup ( mem_ctx , get_global_sam_name ( ) ) ;
2007-11-27 18:36:06 +03:00
return true ;
2005-11-27 00:02:48 +03:00
}
2005-11-26 23:28:12 +03:00
if ( sid_check_is_builtin ( sid ) ) {
2006-02-04 01:19:41 +03:00
* name = talloc_strdup ( mem_ctx , builtin_domain_name ( ) ) ;
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
2003-08-28 00:52:56 +04:00
2006-02-04 01:19:41 +03:00
if ( sid_check_is_wellknown_domain ( sid , & tmp ) ) {
* name = talloc_strdup ( mem_ctx , tmp ) ;
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
2003-08-28 00:52:56 +04:00
2008-01-25 03:40:42 +03:00
if ( sid_check_is_unix_users ( sid ) ) {
* name = talloc_strdup ( mem_ctx , unix_users_domain_name ( ) ) ;
return true ;
}
if ( sid_check_is_unix_groups ( sid ) ) {
* name = talloc_strdup ( mem_ctx , unix_groups_domain_name ( ) ) ;
return true ;
}
2006-02-04 01:19:41 +03:00
if ( sid - > num_auths ! = 4 ) {
/* This can't be a domain */
2007-11-27 18:36:06 +03:00
return false ;
2005-11-26 23:28:12 +03:00
}
2006-02-04 01:19:41 +03:00
if ( IS_DC ) {
uint32 i , num_domains ;
struct trustdom_info * * domains ;
2005-11-27 00:02:48 +03:00
2006-02-04 01:19:41 +03:00
/* This is relatively expensive, but it happens only on DCs
* and for SIDs that have 4 sub - authorities and thus look like
* domains */
2005-11-26 23:28:12 +03:00
2007-01-16 11:17:26 +03:00
if ( ! NT_STATUS_IS_OK ( pdb_enum_trusteddoms ( mem_ctx ,
& num_domains ,
& domains ) ) ) {
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
2005-11-27 00:02:48 +03:00
2006-02-04 01:19:41 +03:00
for ( i = 0 ; i < num_domains ; i + + ) {
if ( sid_equal ( sid , & domains [ i ] - > sid ) ) {
* name = talloc_strdup ( mem_ctx ,
domains [ i ] - > name ) ;
2007-11-27 18:36:06 +03:00
return true ;
2006-02-04 01:19:41 +03:00
}
}
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
2005-11-27 00:02:48 +03:00
2006-02-04 01:19:41 +03:00
if ( winbind_lookup_sid ( mem_ctx , sid , & tmp , NULL , & type ) & &
( type = = SID_NAME_DOMAIN ) ) {
* name = tmp ;
2007-11-27 18:36:06 +03:00
return true ;
2003-08-28 00:52:56 +04:00
}
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
/*
* This tries to implement the rather weird rules for the lsa_lookup level
* parameter .
*
* This is as close as we can get to what W2k3 does . With this we survive the
* RPC - LSALOOKUP samba4 test as of 2006 - 01 - 08. NT4 as a PDC is a bit more
* different , but I assume that ' s just being too liberal . For example , W2k3
* replies to everything else but the levels 1 - 6 with INVALID_PARAMETER
* whereas NT4 does the same as level 1 ( I think ) . I did not fully test that
* with NT4 , this is what w2k3 does .
*
* Level 1 : Ask everywhere
* Level 2 : Ask domain and trusted domains , no builtin and wkn
* Level 3 : Only ask domain
* Level 4 : W2k3ad : Only ask AD trusts
2007-06-27 16:35:12 +04:00
* Level 5 : Only ask transitive forest trusts
2006-02-04 01:19:41 +03:00
* Level 6 : Like 4
*/
2010-05-21 05:25:01 +04:00
static bool check_dom_sid_to_level ( const struct dom_sid * sid , int level )
2006-02-04 01:19:41 +03:00
{
2007-11-27 18:36:06 +03:00
int ret = false ;
2006-02-04 01:19:41 +03:00
switch ( level ) {
case 1 :
2007-11-27 18:36:06 +03:00
ret = true ;
2006-02-04 01:19:41 +03:00
break ;
case 2 :
ret = ( ! sid_check_is_builtin ( sid ) & &
! sid_check_is_wellknown_domain ( sid , NULL ) ) ;
break ;
case 3 :
case 4 :
case 6 :
ret = sid_check_is_domain ( sid ) ;
break ;
case 5 :
2007-11-27 18:36:06 +03:00
ret = false ;
2006-02-04 01:19:41 +03:00
break ;
2005-09-30 21:13:37 +04:00
}
2003-08-28 00:52:56 +04:00
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " %s SID %s in level %d \n " ,
ret ? " Accepting " : " Rejecting " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( sid ) , level ) ) ;
2006-02-04 01:19:41 +03:00
return ret ;
}
2003-08-28 00:52:56 +04:00
2006-02-04 01:19:41 +03:00
/*
* Lookup a bunch of SIDs . This is modeled after lsa_lookup_sids with
* references to domains , it is explicitly made for this .
*
* This attempts to be as efficient as possible : It collects all SIDs
* belonging to a domain and hands them in bulk to the appropriate lookup
* function . In particular pdb_lookup_rids with ldapsam_trusted benefits
* * hugely * from this . Winbind is going to be extended with a lookup_rids
* interface as well , so on a DC we can do a bulk lsa_lookuprids to the
* appropriate DC .
*/
NTSTATUS lookup_sids ( TALLOC_CTX * mem_ctx , int num_sids ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * * sids , int level ,
2006-02-04 01:19:41 +03:00
struct lsa_dom_info * * ret_domains ,
struct lsa_name_info * * ret_names )
{
TALLOC_CTX * tmp_ctx ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
struct lsa_name_info * name_infos ;
2007-04-30 21:19:49 +04:00
struct lsa_dom_info * dom_infos = NULL ;
2006-02-04 01:19:41 +03:00
int i , j ;
2006-07-11 22:01:26 +04:00
if ( ! ( tmp_ctx = talloc_new ( mem_ctx ) ) ) {
2006-02-04 01:19:41 +03:00
DEBUG ( 0 , ( " talloc_new failed \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
2003-08-28 00:52:56 +04:00
}
2005-09-30 21:13:37 +04:00
2007-04-30 06:39:34 +04:00
if ( num_sids ) {
name_infos = TALLOC_ARRAY ( mem_ctx , struct lsa_name_info , num_sids ) ;
if ( name_infos = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
goto fail ;
}
} else {
name_infos = NULL ;
}
2006-07-11 22:01:26 +04:00
dom_infos = TALLOC_ZERO_ARRAY ( mem_ctx , struct lsa_dom_info ,
2008-10-24 04:01:16 +04:00
LSA_REF_DOMAIN_LIST_MULTIPLIER ) ;
2007-04-30 06:39:34 +04:00
if ( dom_infos = = NULL ) {
2006-02-04 01:19:41 +03:00
result = NT_STATUS_NO_MEMORY ;
2006-07-11 22:01:26 +04:00
goto fail ;
2006-02-04 01:19:41 +03:00
}
/* First build up the data structures:
*
* dom_infos is a list of domains referenced in the list of
* SIDs . Later we will walk the list of domains and look up the RIDs
* in bulk .
*
* name_infos is a shadow - copy of the SIDs array to collect the real
* data .
*
* dom_info - > idxs is an index into the name_infos array . The
* difficulty we have here is that we need to keep the SIDs the client
* asked for in the same order for the reply
*/
for ( i = 0 ; i < num_sids ; i + + ) {
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2010-06-07 12:03:50 +04:00
uint32_t rid = 0 ;
2006-02-04 01:19:41 +03:00
const char * domain_name = NULL ;
sid_copy ( & sid , sids [ i ] ) ;
name_infos [ i ] . type = SID_NAME_USE_NONE ;
if ( lookup_as_domain ( & sid , name_infos , & domain_name ) ) {
/* We can't push that through the normal lookup
* process , as this would reference illegal
* domains .
*
* For example S - 1 - 5 - 32 would end up referencing
* domain S - 1 - 5 - with RID 32 which is clearly wrong .
*/
if ( domain_name = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
2006-07-11 22:01:26 +04:00
goto fail ;
2006-02-04 01:19:41 +03:00
}
name_infos [ i ] . rid = 0 ;
name_infos [ i ] . type = SID_NAME_DOMAIN ;
name_infos [ i ] . name = NULL ;
if ( sid_check_is_builtin ( & sid ) ) {
/* Yes, W2k3 returns "BUILTIN" both as domain
* and name here */
name_infos [ i ] . name = talloc_strdup (
name_infos , builtin_domain_name ( ) ) ;
if ( name_infos [ i ] . name = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
2006-07-11 22:01:26 +04:00
goto fail ;
2006-02-04 01:19:41 +03:00
}
}
} else {
/* This is a normal SID with rid component */
if ( ! sid_split_rid ( & sid , & rid ) ) {
2009-03-24 13:07:16 +03:00
result = NT_STATUS_INVALID_SID ;
2006-07-11 22:01:26 +04:00
goto fail ;
2006-02-04 01:19:41 +03:00
}
}
if ( ! check_dom_sid_to_level ( & sid , level ) ) {
name_infos [ i ] . rid = 0 ;
name_infos [ i ] . type = SID_NAME_UNKNOWN ;
name_infos [ i ] . name = NULL ;
continue ;
}
2008-10-24 04:01:16 +04:00
for ( j = 0 ; j < LSA_REF_DOMAIN_LIST_MULTIPLIER ; j + + ) {
2006-02-04 01:19:41 +03:00
if ( ! dom_infos [ j ] . valid ) {
break ;
}
if ( sid_equal ( & sid , & dom_infos [ j ] . sid ) ) {
break ;
}
}
2008-10-24 04:01:16 +04:00
if ( j = = LSA_REF_DOMAIN_LIST_MULTIPLIER ) {
2006-02-04 01:19:41 +03:00
/* TODO: What's the right error message here? */
result = NT_STATUS_NONE_MAPPED ;
2006-07-11 22:01:26 +04:00
goto fail ;
2006-02-04 01:19:41 +03:00
}
if ( ! dom_infos [ j ] . valid ) {
/* We found a domain not yet referenced, create a new
* ref . */
2007-11-27 18:36:06 +03:00
dom_infos [ j ] . valid = true ;
2006-02-04 01:19:41 +03:00
sid_copy ( & dom_infos [ j ] . sid , & sid ) ;
if ( domain_name ! = NULL ) {
/* This name was being found above in the case
* when we found a domain SID */
dom_infos [ j ] . name =
2006-07-11 22:01:26 +04:00
talloc_strdup ( dom_infos , domain_name ) ;
if ( dom_infos [ j ] . name = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2006-02-04 01:19:41 +03:00
} else {
/* lookup_rids will take care of this */
dom_infos [ j ] . name = NULL ;
}
}
name_infos [ i ] . dom_idx = j ;
if ( name_infos [ i ] . type = = SID_NAME_USE_NONE ) {
name_infos [ i ] . rid = rid ;
ADD_TO_ARRAY ( dom_infos , int , i , & dom_infos [ j ] . idxs ,
& dom_infos [ j ] . num_idxs ) ;
if ( dom_infos [ j ] . idxs = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
2006-07-11 22:01:26 +04:00
goto fail ;
2006-02-04 01:19:41 +03:00
}
}
}
/* Iterate over the domains found */
2008-10-24 04:01:16 +04:00
for ( i = 0 ; i < LSA_REF_DOMAIN_LIST_MULTIPLIER ; i + + ) {
2006-02-04 01:19:41 +03:00
uint32_t * rids ;
2006-07-11 22:01:26 +04:00
const char * domain_name = NULL ;
2006-02-04 01:19:41 +03:00
const char * * names ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType * types ;
2006-02-04 01:19:41 +03:00
struct lsa_dom_info * dom = & dom_infos [ i ] ;
if ( ! dom - > valid ) {
/* No domains left, we're done */
break ;
}
2007-04-30 06:39:34 +04:00
if ( dom - > num_idxs ) {
if ( ! ( rids = TALLOC_ARRAY ( tmp_ctx , uint32 , dom - > num_idxs ) ) ) {
result = NT_STATUS_NO_MEMORY ;
goto fail ;
}
} else {
rids = NULL ;
2006-02-04 01:19:41 +03:00
}
for ( j = 0 ; j < dom - > num_idxs ; j + + ) {
rids [ j ] = name_infos [ dom - > idxs [ j ] ] . rid ;
}
if ( ! lookup_rids ( tmp_ctx , & dom - > sid ,
2006-07-11 22:01:26 +04:00
dom - > num_idxs , rids , & domain_name ,
2006-02-04 01:19:41 +03:00
& names , & types ) ) {
result = NT_STATUS_NO_MEMORY ;
2006-07-11 22:01:26 +04:00
goto fail ;
2006-02-04 01:19:41 +03:00
}
2006-07-11 22:01:26 +04:00
if ( ! ( dom - > name = talloc_strdup ( dom_infos , domain_name ) ) ) {
result = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2006-02-04 01:19:41 +03:00
for ( j = 0 ; j < dom - > num_idxs ; j + + ) {
int idx = dom - > idxs [ j ] ;
name_infos [ idx ] . type = types [ j ] ;
if ( types [ j ] ! = SID_NAME_UNKNOWN ) {
name_infos [ idx ] . name =
2006-07-11 22:01:26 +04:00
talloc_strdup ( name_infos , names [ j ] ) ;
if ( name_infos [ idx ] . name = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2006-02-04 01:19:41 +03:00
} else {
name_infos [ idx ] . name = NULL ;
}
}
}
2006-07-11 22:01:26 +04:00
* ret_domains = dom_infos ;
* ret_names = name_infos ;
2007-10-27 04:58:28 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2006-07-11 22:01:26 +04:00
return NT_STATUS_OK ;
2006-02-04 01:19:41 +03:00
2006-07-11 22:01:26 +04:00
fail :
TALLOC_FREE ( dom_infos ) ;
TALLOC_FREE ( name_infos ) ;
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( tmp_ctx ) ;
2006-02-04 01:19:41 +03:00
return result ;
}
2005-12-03 21:34:13 +03:00
2006-02-04 01:19:41 +03:00
/*****************************************************************
* THE CANONICAL * convert SID to name function .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-12-03 21:34:13 +03:00
2010-05-21 05:25:01 +04:00
bool lookup_sid ( TALLOC_CTX * mem_ctx , const struct dom_sid * sid ,
2006-02-04 01:19:41 +03:00
const char * * ret_domain , const char * * ret_name ,
2006-09-08 18:28:06 +04:00
enum lsa_SidType * ret_type )
2006-02-04 01:19:41 +03:00
{
struct lsa_dom_info * domain ;
struct lsa_name_info * name ;
TALLOC_CTX * tmp_ctx ;
2007-11-27 18:36:06 +03:00
bool ret = false ;
2006-02-04 01:19:41 +03:00
2008-01-25 03:40:01 +03:00
DEBUG ( 10 , ( " lookup_sid called for SID '%s' \n " , sid_string_dbg ( sid ) ) ) ;
2006-07-11 22:01:26 +04:00
if ( ! ( tmp_ctx = talloc_new ( mem_ctx ) ) ) {
2006-02-04 01:19:41 +03:00
DEBUG ( 0 , ( " talloc_new failed \n " ) ) ;
2007-11-27 18:36:06 +03:00
return false ;
2005-12-03 21:34:13 +03:00
}
2006-02-04 01:19:41 +03:00
if ( ! NT_STATUS_IS_OK ( lookup_sids ( tmp_ctx , 1 , & sid , 1 ,
& domain , & name ) ) ) {
goto done ;
}
if ( name - > type = = SID_NAME_UNKNOWN ) {
goto done ;
}
2006-07-11 22:01:26 +04:00
if ( ( ret_domain ! = NULL ) & &
! ( * ret_domain = talloc_strdup ( mem_ctx , domain - > name ) ) ) {
goto done ;
2005-12-03 21:34:13 +03:00
}
2006-07-11 22:01:26 +04:00
if ( ( ret_name ! = NULL ) & &
! ( * ret_name = talloc_strdup ( mem_ctx , name - > name ) ) ) {
goto done ;
2005-12-03 21:34:13 +03:00
}
if ( ret_type ! = NULL ) {
2006-02-04 01:19:41 +03:00
* ret_type = name - > type ;
2005-12-03 21:34:13 +03:00
}
2007-11-27 18:36:06 +03:00
ret = true ;
2006-02-04 01:19:41 +03:00
done :
if ( ret ) {
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " Sid %s -> %s \\ %s(%d) \n " , sid_string_dbg ( sid ) ,
domain - > name , name - > name , name - > type ) ) ;
2006-02-04 01:19:41 +03:00
} else {
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " failed to lookup sid %s \n " , sid_string_dbg ( sid ) ) ) ;
2006-02-04 01:19:41 +03:00
}
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( tmp_ctx ) ;
2006-02-04 01:19:41 +03:00
return ret ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
Id mapping cache . This is to avoid Winbind mappings already
seen by smbd to be queried too frequently , keeping winbindd
busy , and blocking smbd while winbindd is busy with other
stuff . Written by Michael Steffens < michael . steffens @ hp . com > ,
modified to use linked lists by jra .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*****************************************************************
Find a SID given a uid .
2007-12-22 16:52:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-28 00:52:56 +04:00
2010-05-21 05:25:01 +04:00
static bool fetch_sid_from_uid_cache ( struct dom_sid * psid , uid_t uid )
2003-08-28 00:52:56 +04:00
{
2007-12-22 16:52:34 +03:00
DATA_BLOB cache_value ;
if ( ! memcache_lookup ( NULL , UID_SID_CACHE ,
data_blob_const ( & uid , sizeof ( uid ) ) ,
& cache_value ) ) {
return false ;
2003-08-28 00:52:56 +04:00
}
2007-12-22 16:52:34 +03:00
2008-05-06 15:53:45 +04:00
memcpy ( psid , cache_value . data , MIN ( sizeof ( * psid ) , cache_value . length ) ) ;
SMB_ASSERT ( cache_value . length > = offsetof ( struct dom_sid , id_auth ) ) ;
2010-05-10 02:42:06 +04:00
SMB_ASSERT ( cache_value . length = = ndr_size_dom_sid ( psid , 0 ) ) ;
2007-12-22 16:52:34 +03:00
return true ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
Find a uid given a SID .
2007-12-22 16:52:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-28 00:52:56 +04:00
2010-05-21 05:25:01 +04:00
static bool fetch_uid_from_cache ( uid_t * puid , const struct dom_sid * psid )
2003-08-28 00:52:56 +04:00
{
2007-12-22 16:52:34 +03:00
DATA_BLOB cache_value ;
if ( ! memcache_lookup ( NULL , SID_UID_CACHE ,
2010-05-10 02:42:06 +04:00
data_blob_const ( psid , ndr_size_dom_sid ( psid , 0 ) ) ,
2007-12-22 16:52:34 +03:00
& cache_value ) ) {
return false ;
2003-08-28 00:52:56 +04:00
}
2007-12-22 16:52:34 +03:00
SMB_ASSERT ( cache_value . length = = sizeof ( * puid ) ) ;
memcpy ( puid , cache_value . data , sizeof ( * puid ) ) ;
return true ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
Store uid to SID mapping in cache .
2007-12-22 16:52:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-28 00:52:56 +04:00
2010-05-21 05:25:01 +04:00
void store_uid_sid_cache ( const struct dom_sid * psid , uid_t uid )
2003-08-28 00:52:56 +04:00
{
2007-12-22 16:52:34 +03:00
memcache_add ( NULL , SID_UID_CACHE ,
2010-05-10 02:42:06 +04:00
data_blob_const ( psid , ndr_size_dom_sid ( psid , 0 ) ) ,
2007-12-22 16:52:34 +03:00
data_blob_const ( & uid , sizeof ( uid ) ) ) ;
memcache_add ( NULL , UID_SID_CACHE ,
data_blob_const ( & uid , sizeof ( uid ) ) ,
2010-05-10 02:42:06 +04:00
data_blob_const ( psid , ndr_size_dom_sid ( psid , 0 ) ) ) ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
Find a SID given a gid .
2007-12-22 16:52:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-28 00:52:56 +04:00
2010-05-21 05:25:01 +04:00
static bool fetch_sid_from_gid_cache ( struct dom_sid * psid , gid_t gid )
2003-08-28 00:52:56 +04:00
{
2007-12-22 16:52:34 +03:00
DATA_BLOB cache_value ;
if ( ! memcache_lookup ( NULL , GID_SID_CACHE ,
data_blob_const ( & gid , sizeof ( gid ) ) ,
& cache_value ) ) {
return false ;
2003-08-28 00:52:56 +04:00
}
2007-12-22 16:52:34 +03:00
2008-05-06 15:53:45 +04:00
memcpy ( psid , cache_value . data , MIN ( sizeof ( * psid ) , cache_value . length ) ) ;
SMB_ASSERT ( cache_value . length > = offsetof ( struct dom_sid , id_auth ) ) ;
2010-05-10 02:42:06 +04:00
SMB_ASSERT ( cache_value . length = = ndr_size_dom_sid ( psid , 0 ) ) ;
2007-12-22 16:52:34 +03:00
return true ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
Find a gid given a SID .
2007-12-22 16:52:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-28 00:52:56 +04:00
2010-05-21 05:25:01 +04:00
static bool fetch_gid_from_cache ( gid_t * pgid , const struct dom_sid * psid )
2003-08-28 00:52:56 +04:00
{
2007-12-22 16:52:34 +03:00
DATA_BLOB cache_value ;
2009-06-26 16:09:10 +04:00
if ( ! memcache_lookup ( NULL , SID_GID_CACHE ,
2010-05-10 02:42:06 +04:00
data_blob_const ( psid , ndr_size_dom_sid ( psid , 0 ) ) ,
2007-12-22 16:52:34 +03:00
& cache_value ) ) {
return false ;
2003-08-28 00:52:56 +04:00
}
2007-12-22 16:52:34 +03:00
SMB_ASSERT ( cache_value . length = = sizeof ( * pgid ) ) ;
memcpy ( pgid , cache_value . data , sizeof ( * pgid ) ) ;
return true ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
Store gid to SID mapping in cache .
2007-12-22 16:52:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-28 00:52:56 +04:00
2010-05-21 05:25:01 +04:00
void store_gid_sid_cache ( const struct dom_sid * psid , gid_t gid )
2003-08-28 00:52:56 +04:00
{
2007-12-22 16:52:34 +03:00
memcache_add ( NULL , SID_GID_CACHE ,
2010-05-10 02:42:06 +04:00
data_blob_const ( psid , ndr_size_dom_sid ( psid , 0 ) ) ,
2007-12-22 16:52:34 +03:00
data_blob_const ( & gid , sizeof ( gid ) ) ) ;
memcache_add ( NULL , GID_SID_CACHE ,
data_blob_const ( & gid , sizeof ( gid ) ) ,
2010-05-10 02:42:06 +04:00
data_blob_const ( psid , ndr_size_dom_sid ( psid , 0 ) ) ) ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE LEGACY * convert uid_t to SID function .
2003-08-28 00:52:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
static void legacy_uid_to_sid ( struct dom_sid * psid , uid_t uid )
2003-08-28 00:52:56 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret ;
2003-08-28 00:52:56 +04:00
ZERO_STRUCTP ( psid ) ;
2007-04-06 03:56:10 +04:00
become_root ( ) ;
2009-11-14 03:06:35 +03:00
ret = pdb_uid_to_sid ( uid , psid ) ;
2007-04-06 03:56:10 +04:00
unbecome_root ( ) ;
2006-09-13 20:30:40 +04:00
if ( ret ) {
2006-02-04 01:19:41 +03:00
/* This is a mapped user */
goto done ;
2003-08-28 00:52:56 +04:00
}
2006-08-22 00:04:01 +04:00
/* This is an unmapped user */
uid_to_unix_users_sid ( uid , psid ) ;
2006-02-04 01:19:41 +03:00
done :
2006-12-12 17:52:13 +03:00
DEBUG ( 10 , ( " LEGACY: uid %u -> sid %s \n " , ( unsigned int ) uid ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( psid ) ) ) ;
2003-08-28 00:52:56 +04:00
2006-12-14 18:30:54 +03:00
store_uid_sid_cache ( psid , uid ) ;
2006-02-04 01:19:41 +03:00
return ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE LEGACY * convert gid_t to SID function .
2003-08-28 00:52:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
static void legacy_gid_to_sid ( struct dom_sid * psid , gid_t gid )
2003-08-28 00:52:56 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret ;
2003-08-28 00:52:56 +04:00
ZERO_STRUCTP ( psid ) ;
2007-04-06 03:56:10 +04:00
become_root ( ) ;
2006-09-13 20:30:40 +04:00
ret = pdb_gid_to_sid ( gid , psid ) ;
2007-04-06 03:56:10 +04:00
unbecome_root ( ) ;
2006-09-13 20:30:40 +04:00
if ( ret ) {
2006-02-04 01:19:41 +03:00
/* This is a mapped group */
goto done ;
2003-08-28 00:52:56 +04:00
}
2006-08-22 00:04:01 +04:00
/* This is an unmapped group */
2003-08-28 00:52:56 +04:00
2006-08-22 19:18:13 +04:00
gid_to_unix_groups_sid ( gid , psid ) ;
2006-02-04 01:19:41 +03:00
done :
2006-12-12 17:52:13 +03:00
DEBUG ( 10 , ( " LEGACY: gid %u -> sid %s \n " , ( unsigned int ) gid ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( psid ) ) ) ;
2003-08-28 00:52:56 +04:00
2006-12-14 18:30:54 +03:00
store_gid_sid_cache ( psid , gid ) ;
2006-02-04 01:19:41 +03:00
return ;
2003-08-28 00:52:56 +04:00
}
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE LEGACY * convert SID to uid function .
2003-08-28 00:52:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
static bool legacy_sid_to_uid ( const struct dom_sid * psid , uid_t * puid )
2003-08-28 00:52:56 +04:00
{
2006-09-08 18:28:06 +04:00
enum lsa_SidType type ;
2003-08-28 00:52:56 +04:00
2010-01-10 19:57:00 +03:00
if ( sid_check_is_in_our_domain ( psid ) ) {
2006-02-04 01:19:41 +03:00
union unid_t id ;
2007-10-19 04:40:25 +04:00
bool ret ;
2006-02-04 01:19:41 +03:00
2007-04-06 03:56:10 +04:00
become_root ( ) ;
2006-09-13 20:30:40 +04:00
ret = pdb_sid_to_id ( psid , & id , & type ) ;
2007-04-06 03:56:10 +04:00
unbecome_root ( ) ;
2006-09-13 20:30:40 +04:00
if ( ret ) {
2006-02-04 01:19:41 +03:00
if ( type ! = SID_NAME_USER ) {
DEBUG ( 5 , ( " sid %s is a %s, expected a user \n " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( psid ) ,
2006-02-04 01:19:41 +03:00
sid_type_lookup ( type ) ) ) ;
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
* puid = id . uid ;
goto done ;
}
2003-08-28 00:52:56 +04:00
2006-08-22 00:04:01 +04:00
/* This was ours, but it was not mapped. Fail */
2003-08-28 00:52:56 +04:00
}
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " LEGACY: mapping failed for sid %s \n " ,
sid_string_dbg ( psid ) ) ) ;
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
2006-12-14 18:30:54 +03:00
done :
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " LEGACY: sid %s -> uid %u \n " , sid_string_dbg ( psid ) ,
( unsigned int ) * puid ) ) ;
2003-08-28 00:52:56 +04:00
2006-12-14 18:30:54 +03:00
store_uid_sid_cache ( psid , * puid ) ;
2007-11-27 18:36:06 +03:00
return true ;
2003-08-28 00:52:56 +04:00
}
2006-02-04 01:19:41 +03:00
2003-08-28 00:52:56 +04:00
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE LEGACY * convert SID to gid function .
Group mapping is used for gids that maps to Wellknown SIDs
2003-08-28 00:52:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
static bool legacy_sid_to_gid ( const struct dom_sid * psid , gid_t * pgid )
2003-08-28 00:52:56 +04:00
{
2006-02-04 01:19:41 +03:00
GROUP_MAP map ;
union unid_t id ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType type ;
2006-02-04 01:19:41 +03:00
2006-03-02 21:33:43 +03:00
if ( ( sid_check_is_in_builtin ( psid ) | |
sid_check_is_in_wellknown_domain ( psid ) ) ) {
2007-10-19 04:40:25 +04:00
bool ret ;
2006-09-13 20:30:40 +04:00
2007-04-06 03:56:10 +04:00
become_root ( ) ;
2006-09-13 20:30:40 +04:00
ret = pdb_getgrsid ( & map , * psid ) ;
2007-04-06 03:56:10 +04:00
unbecome_root ( ) ;
2006-09-13 20:30:40 +04:00
if ( ret ) {
2006-03-02 21:33:43 +03:00
* pgid = map . gid ;
goto done ;
}
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " LEGACY: mapping failed for sid %s \n " ,
sid_string_dbg ( psid ) ) ) ;
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
2003-08-28 00:52:56 +04:00
2010-01-10 19:57:00 +03:00
if ( sid_check_is_in_our_domain ( psid ) ) {
2007-10-19 04:40:25 +04:00
bool ret ;
2006-09-13 20:30:40 +04:00
2007-04-06 03:56:10 +04:00
become_root ( ) ;
2006-09-13 20:30:40 +04:00
ret = pdb_sid_to_id ( psid , & id , & type ) ;
2007-04-06 03:56:10 +04:00
unbecome_root ( ) ;
2006-09-13 20:30:40 +04:00
if ( ret ) {
2006-02-04 01:19:41 +03:00
if ( ( type ! = SID_NAME_DOM_GRP ) & &
( type ! = SID_NAME_ALIAS ) ) {
2007-12-15 23:11:36 +03:00
DEBUG ( 5 , ( " LEGACY: sid %s is a %s, expected "
" a group \n " , sid_string_dbg ( psid ) ,
2006-02-04 01:19:41 +03:00
sid_type_lookup ( type ) ) ) ;
2007-11-27 18:36:06 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
* pgid = id . gid ;
goto done ;
}
2006-12-14 18:30:54 +03:00
2006-08-22 00:04:01 +04:00
/* This was ours, but it was not mapped. Fail */
2006-02-04 01:19:41 +03:00
}
2006-12-14 18:30:54 +03:00
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " LEGACY: mapping failed for sid %s \n " ,
sid_string_dbg ( psid ) ) ) ;
2007-11-27 18:36:06 +03:00
return false ;
2004-05-28 12:57:00 +04:00
2006-12-12 17:52:13 +03:00
done :
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " LEGACY: sid %s -> gid %u \n " , sid_string_dbg ( psid ) ,
2006-12-12 17:52:13 +03:00
( unsigned int ) * pgid ) ) ;
2006-12-14 18:30:54 +03:00
store_gid_sid_cache ( psid , * pgid ) ;
2007-11-27 18:36:06 +03:00
return true ;
2006-12-12 17:52:13 +03:00
}
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE CANONICAL * convert uid_t to SID function .
2006-12-12 17:52:13 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
void uid_to_sid ( struct dom_sid * psid , uid_t uid )
2006-12-12 17:52:13 +03:00
{
2008-08-27 01:52:11 +04:00
bool expired = true ;
2008-08-27 02:51:56 +04:00
bool ret ;
2006-12-12 17:52:13 +03:00
ZERO_STRUCTP ( psid ) ;
if ( fetch_sid_from_uid_cache ( psid , uid ) )
return ;
2008-08-27 01:52:11 +04:00
/* Check the winbindd cache directly. */
2008-08-27 02:51:56 +04:00
ret = idmap_cache_find_uid2sid ( uid , psid , & expired ) ;
2008-08-27 05:05:34 +04:00
if ( ret & & ! expired & & is_null_sid ( psid ) ) {
2008-08-27 03:14:25 +04:00
/*
* Negative cache entry , we already asked .
* do legacy .
*/
legacy_uid_to_sid ( psid , uid ) ;
return ;
}
if ( ! ret | | expired ) {
2008-08-27 01:52:11 +04:00
/* Not in cache. Ask winbindd. */
if ( ! winbind_uid_to_sid ( psid , uid ) ) {
2009-03-03 03:50:19 +03:00
/*
2009-03-04 03:47:48 +03:00
* We shouldn ' t return the NULL SID
* here if winbind was running and
* couldn ' t map , as winbind will have
* added a negative entry that will
* cause us to go though the
* legacy_uid_to_sid ( )
* function anyway in the case above
* the next time we ask .
*/
DEBUG ( 5 , ( " uid_to_sid: winbind failed to find a sid "
2009-05-12 08:56:57 +04:00
" for uid %u \n " , ( unsigned int ) uid ) ) ;
2009-03-04 03:47:48 +03:00
2009-03-03 03:50:19 +03:00
legacy_uid_to_sid ( psid , uid ) ;
2006-12-16 14:15:03 +03:00
return ;
2006-12-12 17:52:13 +03:00
}
}
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " uid %u -> sid %s \n " , ( unsigned int ) uid ,
sid_string_dbg ( psid ) ) ) ;
2006-12-12 17:52:13 +03:00
store_uid_sid_cache ( psid , uid ) ;
return ;
}
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE CANONICAL * convert gid_t to SID function .
2006-12-12 17:52:13 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
void gid_to_sid ( struct dom_sid * psid , gid_t gid )
2006-12-12 17:52:13 +03:00
{
2008-08-27 01:52:11 +04:00
bool expired = true ;
2008-08-27 02:51:56 +04:00
bool ret ;
2006-12-12 17:52:13 +03:00
ZERO_STRUCTP ( psid ) ;
if ( fetch_sid_from_gid_cache ( psid , gid ) )
return ;
2008-08-27 01:52:11 +04:00
/* Check the winbindd cache directly. */
2008-08-27 02:51:56 +04:00
ret = idmap_cache_find_gid2sid ( gid , psid , & expired ) ;
2008-08-27 05:05:34 +04:00
if ( ret & & ! expired & & is_null_sid ( psid ) ) {
2008-08-27 03:14:25 +04:00
/*
* Negative cache entry , we already asked .
* do legacy .
*/
legacy_gid_to_sid ( psid , gid ) ;
return ;
}
if ( ! ret | | expired ) {
2008-08-27 01:52:11 +04:00
/* Not in cache. Ask winbindd. */
if ( ! winbind_gid_to_sid ( psid , gid ) ) {
2009-03-03 03:50:19 +03:00
/*
2009-03-04 03:47:48 +03:00
* We shouldn ' t return the NULL SID
* here if winbind was running and
* couldn ' t map , as winbind will have
* added a negative entry that will
* cause us to go though the
* legacy_gid_to_sid ( )
* function anyway in the case above
* the next time we ask .
*/
DEBUG ( 5 , ( " gid_to_sid: winbind failed to find a sid "
2009-05-12 08:56:57 +04:00
" for gid %u \n " , ( unsigned int ) gid ) ) ;
2009-03-04 03:47:48 +03:00
2009-03-03 03:50:19 +03:00
legacy_gid_to_sid ( psid , gid ) ;
2006-12-16 14:15:03 +03:00
return ;
2006-12-12 17:52:13 +03:00
}
}
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " gid %u -> sid %s \n " , ( unsigned int ) gid ,
sid_string_dbg ( psid ) ) ) ;
2008-08-27 01:52:11 +04:00
2006-12-12 17:52:13 +03:00
store_gid_sid_cache ( psid , gid ) ;
return ;
}
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE CANONICAL * convert SID to uid function .
2006-12-12 17:52:13 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
bool sid_to_uid ( const struct dom_sid * psid , uid_t * puid )
2006-12-12 17:52:13 +03:00
{
2008-08-27 01:52:11 +04:00
bool expired = true ;
2008-08-27 02:51:56 +04:00
bool ret ;
2008-07-11 19:44:52 +04:00
uint32 rid ;
2006-12-12 17:52:13 +03:00
gid_t gid ;
if ( fetch_uid_from_cache ( puid , psid ) )
2007-11-27 18:36:06 +03:00
return true ;
2006-12-12 17:52:13 +03:00
if ( fetch_gid_from_cache ( & gid , psid ) ) {
2007-11-27 18:36:06 +03:00
return false ;
2003-08-28 00:52:56 +04:00
}
2007-05-22 00:51:15 +04:00
/* Optimize for the Unix Users Domain
* as the conversion is straightforward */
2008-07-11 19:44:52 +04:00
if ( sid_peek_check_rid ( & global_sid_Unix_Users , psid , & rid ) ) {
uid_t uid = rid ;
* puid = uid ;
2007-05-22 00:51:15 +04:00
/* return here, don't cache */
2008-07-11 19:44:52 +04:00
DEBUG ( 10 , ( " sid %s -> uid %u \n " , sid_string_dbg ( psid ) ,
( unsigned int ) * puid ) ) ;
2007-11-27 18:36:06 +03:00
return true ;
2007-05-22 00:51:15 +04:00
}
2008-08-27 01:52:11 +04:00
/* Check the winbindd cache directly. */
2008-08-27 02:51:56 +04:00
ret = idmap_cache_find_sid2uid ( psid , puid , & expired ) ;
2003-08-28 00:52:56 +04:00
2008-08-27 05:05:34 +04:00
if ( ret & & ! expired & & ( * puid = = ( uid_t ) - 1 ) ) {
2008-08-27 03:14:25 +04:00
/*
* Negative cache entry , we already asked .
* do legacy .
*/
return legacy_sid_to_uid ( psid , puid ) ;
}
if ( ! ret | | expired ) {
2008-08-27 01:52:11 +04:00
/* Not in cache. Ask winbindd. */
if ( ! winbind_sid_to_uid ( puid , psid ) ) {
DEBUG ( 5 , ( " winbind failed to find a uid for sid %s \n " ,
sid_string_dbg ( psid ) ) ) ;
2009-04-17 00:42:40 +04:00
/* winbind failed. do legacy */
return legacy_sid_to_uid ( psid , puid ) ;
2008-08-27 01:52:11 +04:00
}
2003-08-28 00:52:56 +04:00
}
2006-12-12 17:52:13 +03:00
/* TODO: Here would be the place to allocate both a gid and a uid for
* the SID in question */
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " sid %s -> uid %u \n " , sid_string_dbg ( psid ) ,
2006-12-12 17:52:13 +03:00
( unsigned int ) * puid ) ) ;
store_uid_sid_cache ( psid , * puid ) ;
2007-11-27 18:36:06 +03:00
return true ;
2006-12-12 17:52:13 +03:00
}
/*****************************************************************
2008-07-11 19:44:44 +04:00
* THE CANONICAL * convert SID to gid function .
Group mapping is used for gids that maps to Wellknown SIDs
2006-12-12 17:52:13 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
bool sid_to_gid ( const struct dom_sid * psid , gid_t * pgid )
2006-12-12 17:52:13 +03:00
{
2008-08-27 01:52:11 +04:00
bool expired = true ;
2008-08-27 02:51:56 +04:00
bool ret ;
2008-07-11 19:43:54 +04:00
uint32 rid ;
2006-12-12 17:52:13 +03:00
uid_t uid ;
if ( fetch_gid_from_cache ( pgid , psid ) )
2007-11-27 18:36:06 +03:00
return true ;
2006-12-12 17:52:13 +03:00
if ( fetch_uid_from_cache ( & uid , psid ) )
2007-11-27 18:36:06 +03:00
return false ;
2006-12-12 17:52:13 +03:00
2007-05-22 00:51:15 +04:00
/* Optimize for the Unix Groups Domain
* as the conversion is straightforward */
2008-07-11 19:44:52 +04:00
if ( sid_peek_check_rid ( & global_sid_Unix_Groups , psid , & rid ) ) {
gid_t gid = rid ;
* pgid = gid ;
2007-05-22 00:51:15 +04:00
/* return here, don't cache */
2008-07-11 19:44:52 +04:00
DEBUG ( 10 , ( " sid %s -> gid %u \n " , sid_string_dbg ( psid ) ,
( unsigned int ) * pgid ) ) ;
2007-11-27 18:36:06 +03:00
return true ;
2007-05-22 00:51:15 +04:00
}
2008-08-27 01:52:11 +04:00
/* Check the winbindd cache directly. */
2008-08-27 02:51:56 +04:00
ret = idmap_cache_find_sid2gid ( psid , pgid , & expired ) ;
2003-08-28 00:52:56 +04:00
2008-08-27 05:05:34 +04:00
if ( ret & & ! expired & & ( * pgid = = ( gid_t ) - 1 ) ) {
2008-08-27 03:14:25 +04:00
/*
* Negative cache entry , we already asked .
* do legacy .
*/
return legacy_sid_to_gid ( psid , pgid ) ;
}
if ( ! ret | | expired ) {
2008-08-27 02:51:56 +04:00
/* Not in cache or negative. Ask winbindd. */
2008-08-27 01:52:11 +04:00
/* Ask winbindd if it can map this sid to a gid.
* ( Idmap will check it is a valid SID and of the right type ) */
2006-12-12 17:52:13 +03:00
2008-08-27 01:52:11 +04:00
if ( ! winbind_sid_to_gid ( pgid , psid ) ) {
2006-12-12 17:52:13 +03:00
2008-08-27 01:52:11 +04:00
DEBUG ( 10 , ( " winbind failed to find a gid for sid %s \n " ,
sid_string_dbg ( psid ) ) ) ;
2009-04-17 00:42:40 +04:00
/* winbind failed. do legacy */
return legacy_sid_to_gid ( psid , pgid ) ;
2008-08-27 01:52:11 +04:00
}
2003-08-28 00:52:56 +04:00
}
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " sid %s -> gid %u \n " , sid_string_dbg ( psid ) ,
2005-12-03 21:34:13 +03:00
( unsigned int ) * pgid ) ) ;
2003-08-28 00:52:56 +04:00
store_gid_sid_cache ( psid , * pgid ) ;
2007-11-27 18:36:06 +03:00
return true ;
2003-08-28 00:52:56 +04:00
}
2010-05-29 18:51:40 +04:00
/**
* @ brief This function gets the primary group SID mapping the primary
* GID of the user as obtained by an actual getpwnam ( ) call .
* This is necessary to avoid issues with arbitrary group SIDs
* stored in passdb . We try as hard as we can to get the SID
* corresponding to the GID , including trying group mapping .
* If nothing else works , we will force " Domain Users " as the
* primary group .
* This is needed because we must always be able to lookup the
* primary group SID , so we cannot settle for an arbitrary SID .
*
* This call can be expensive . Use with moderation .
* If you have a " samu " struct around use pdb_get_group_sid ( )
* instead as it does properly cache results .
*
* @ param mem_ctx [ in ] The memory context iused to allocate the result .
* @ param username [ in ] The user ' s name
* @ param _pwd [ in | out ] If available , pass in user ' s passwd struct .
* It will contain a tallocated passwd if NULL was
* passed in .
* @ param _group_sid [ out ] The user ' s Primary Group SID
*
* @ return NTSTATUS error code .
*/
NTSTATUS get_primary_group_sid ( TALLOC_CTX * mem_ctx ,
const char * username ,
struct passwd * * _pwd ,
struct dom_sid * * _group_sid )
{
TALLOC_CTX * tmp_ctx ;
bool need_lookup_sid = false ;
struct dom_sid * group_sid ;
struct passwd * pwd = * _pwd ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( ! tmp_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
if ( ! pwd ) {
pwd = Get_Pwnam_alloc ( mem_ctx , username ) ;
if ( ! pwd ) {
DEBUG ( 0 , ( " Failed to find a Unix account for %s " ,
username ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_SUCH_USER ;
}
}
group_sid = talloc_zero ( mem_ctx , struct dom_sid ) ;
if ( ! group_sid ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
gid_to_sid ( group_sid , pwd - > pw_gid ) ;
if ( ! is_null_sid ( group_sid ) ) {
struct dom_sid domain_sid ;
uint32_t rid ;
/* We need a sid within our domain */
sid_copy ( & domain_sid , group_sid ) ;
sid_split_rid ( & domain_sid , & rid ) ;
if ( sid_equal ( & domain_sid , get_global_sam_sid ( ) ) ) {
/*
* As shortcut for the expensive lookup_sid call
* compare the domain sid part
*/
switch ( rid ) {
case DOMAIN_RID_ADMINS :
case DOMAIN_RID_USERS :
goto done ;
default :
need_lookup_sid = true ;
break ;
}
} else {
/* Try group mapping */
ZERO_STRUCTP ( group_sid ) ;
if ( pdb_gid_to_sid ( pwd - > pw_gid , group_sid ) ) {
need_lookup_sid = true ;
}
}
}
/* We must verify that this is a valid SID that resolves to a
* group of the correct type */
if ( need_lookup_sid ) {
enum lsa_SidType type = SID_NAME_UNKNOWN ;
bool lookup_ret ;
DEBUG ( 10 , ( " do lookup_sid(%s) for group of user %s \n " ,
sid_string_dbg ( group_sid ) , username ) ) ;
/* Now check that it's actually a domain group and
* not something else */
lookup_ret = lookup_sid ( tmp_ctx , group_sid ,
NULL , NULL , & type ) ;
if ( lookup_ret & & ( type = = SID_NAME_DOM_GRP ) ) {
goto done ;
}
DEBUG ( 3 , ( " Primary group %s for user %s is "
" a %s and not a domain group \n " ,
sid_string_dbg ( group_sid ) , username ,
sid_type_lookup ( type ) ) ) ;
}
/* Everything else, failed.
* Just set it to the ' Domain Users ' RID of 513 which will
always resolve to a name */
DEBUG ( 3 , ( " Forcing Primary Group to 'Domain Users' for %s \n " ,
username ) ) ;
sid_compose ( group_sid , get_global_sam_sid ( ) , DOMAIN_RID_USERS ) ;
done :
* _pwd = talloc_move ( mem_ctx , & pwd ) ;
* _group_sid = talloc_move ( mem_ctx , & group_sid ) ;
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_OK ;
}