2008-09-16 00:51:44 +04:00
/*
* idmap_hash . c
*
* Copyright ( C ) Gerald Carter < jerry @ samba . org > 2007 - 2008
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*
*/
# include "includes.h"
# include "winbindd/winbindd.h"
2010-08-18 20:13:42 +04:00
# include "idmap.h"
2008-09-16 00:51:44 +04:00
# include "idmap_hash.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
2010-07-01 02:44:15 +04:00
# include "nss_info.h"
2010-10-18 17:55:47 +04:00
# include "../libcli/security/dom_sid.h"
2008-09-16 00:51:44 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_IDMAP
struct sid_hash_table {
2010-05-21 05:25:01 +04:00
struct dom_sid * sid ;
2008-09-16 00:51:44 +04:00
} ;
/*********************************************************************
Hash a domain SID ( S - 1 - 5 - 12 - aaa - bbb - ccc ) to a 12 bit number
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
static uint32_t hash_domain_sid ( const struct dom_sid * sid )
2008-09-16 00:51:44 +04:00
{
uint32_t hash ;
if ( sid - > num_auths ! = 4 )
return 0 ;
/* XOR the last three subauths */
hash = ( ( sid - > sub_auths [ 1 ] ^ sid - > sub_auths [ 2 ] ) ^ sid - > sub_auths [ 3 ] ) ;
/* Take all 32-bits into account when generating the 12-bit
hash value */
hash = ( ( ( hash & 0xFFF00000 ) > > 20 )
+ ( ( hash & 0x000FFF00 ) > > 8 )
+ ( hash & 0x000000FF ) ) & 0x0000FFF ;
/* return a 12-bit hash value */
return hash ;
}
/*********************************************************************
Hash a Relative ID to a 20 bit number
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static uint32_t hash_rid ( uint32_t rid )
{
/* 20 bits for the rid which allows us to support
the first 100 K users / groups in a domain */
return ( rid & 0x0007FFFF ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static uint32_t combine_hashes ( uint32_t h_domain ,
uint32_t h_rid )
{
uint32_t return_id = 0 ;
/* shift the hash_domain 19 bits to the left and OR with the
hash_rid */
return_id = ( ( h_domain < < 19 ) | h_rid ) ;
return return_id ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void separate_hashes ( uint32_t id ,
uint32_t * h_domain ,
uint32_t * h_rid )
{
* h_rid = id & 0x0007FFFF ;
* h_domain = ( id & 0x7FF80000 ) > > 19 ;
return ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-03-03 01:00:58 +03:00
static NTSTATUS be_init ( struct idmap_domain * dom )
2008-09-16 00:51:44 +04:00
{
2011-03-06 14:16:00 +03:00
struct sid_hash_table * hashed_domains ;
2008-09-16 00:51:44 +04:00
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL ;
struct winbindd_tdc_domain * dom_list = NULL ;
size_t num_domains = 0 ;
int i ;
2010-12-06 16:05:49 +03:00
/* If the domain SID hash table has been initialized, assume
2008-09-16 00:51:44 +04:00
that we completed this function previously */
2011-03-06 14:16:00 +03:00
if ( dom - > private_data ! = NULL ) {
2008-09-16 00:51:44 +04:00
nt_status = NT_STATUS_OK ;
goto done ;
}
if ( ! wcache_tdc_fetch_list ( & dom_list , & num_domains ) ) {
nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE ;
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
}
/* Create the hash table of domain SIDs */
2011-06-07 05:58:39 +04:00
hashed_domains = talloc_zero_array ( dom , struct sid_hash_table , 4096 ) ;
2008-09-16 00:51:44 +04:00
BAIL_ON_PTR_NT_ERROR ( hashed_domains , nt_status ) ;
/* create the hash table of domain SIDs */
for ( i = 0 ; i < num_domains ; i + + ) {
uint32_t hash ;
if ( is_null_sid ( & dom_list [ i ] . sid ) )
continue ;
if ( ( hash = hash_domain_sid ( & dom_list [ i ] . sid ) ) = = 0 )
continue ;
DEBUG ( 5 , ( " hash:be_init() Adding %s (%s) -> %d \n " ,
dom_list [ i ] . domain_name ,
sid_string_dbg ( & dom_list [ i ] . sid ) ,
hash ) ) ;
2010-05-21 05:25:01 +04:00
hashed_domains [ hash ] . sid = talloc ( hashed_domains , struct dom_sid ) ;
2008-09-16 00:51:44 +04:00
sid_copy ( hashed_domains [ hash ] . sid , & dom_list [ i ] . sid ) ;
}
2011-03-06 14:16:00 +03:00
dom - > private_data = hashed_domains ;
2008-09-16 00:51:44 +04:00
done :
return nt_status ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS unixids_to_sids ( struct idmap_domain * dom ,
struct id_map * * ids )
{
2011-03-06 14:16:00 +03:00
struct sid_hash_table * hashed_domains = talloc_get_type_abort (
dom - > private_data , struct sid_hash_table ) ;
2008-09-16 00:51:44 +04:00
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL ;
int i ;
2012-06-20 10:42:20 +04:00
if ( ! ids ) {
nt_status = NT_STATUS_INVALID_PARAMETER ;
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
}
2009-03-02 09:19:50 +03:00
/* initialize the status to avoid suprise */
for ( i = 0 ; ids [ i ] ; i + + ) {
ids [ i ] - > status = ID_UNKNOWN ;
}
2011-02-26 14:36:19 +03:00
2011-03-03 01:00:58 +03:00
nt_status = be_init ( dom ) ;
2008-09-16 00:51:44 +04:00
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
for ( i = 0 ; ids [ i ] ; i + + ) {
uint32_t h_domain , h_rid ;
ids [ i ] - > status = ID_UNMAPPED ;
separate_hashes ( ids [ i ] - > xid . id , & h_domain , & h_rid ) ;
/* Make sure the caller allocated memor for us */
if ( ! ids [ i ] - > sid ) {
nt_status = NT_STATUS_INVALID_PARAMETER ;
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
}
/* If the domain hash doesn't find a SID in the table,
skip it */
if ( ! hashed_domains [ h_domain ] . sid )
continue ;
2010-01-10 19:39:27 +03:00
sid_compose ( ids [ i ] - > sid , hashed_domains [ h_domain ] . sid , h_rid ) ;
2008-09-16 00:51:44 +04:00
ids [ i ] - > status = ID_MAPPED ;
}
done :
return nt_status ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS sids_to_unixids ( struct idmap_domain * dom ,
struct id_map * * ids )
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL ;
int i ;
2012-06-20 10:43:36 +04:00
if ( ! ids ) {
nt_status = NT_STATUS_INVALID_PARAMETER ;
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
}
2009-03-02 09:19:50 +03:00
/* initialize the status to avoid suprise */
for ( i = 0 ; ids [ i ] ; i + + ) {
ids [ i ] - > status = ID_UNKNOWN ;
}
2011-02-26 14:36:19 +03:00
2011-03-03 01:00:58 +03:00
nt_status = be_init ( dom ) ;
2008-09-16 00:51:44 +04:00
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
for ( i = 0 ; ids [ i ] ; i + + ) {
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2008-09-16 00:51:44 +04:00
uint32_t rid ;
uint32_t h_domain , h_rid ;
ids [ i ] - > status = ID_UNMAPPED ;
sid_copy ( & sid , ids [ i ] - > sid ) ;
sid_split_rid ( & sid , & rid ) ;
h_domain = hash_domain_sid ( & sid ) ;
h_rid = hash_rid ( rid ) ;
/* Check that both hashes are non-zero*/
if ( h_domain & & h_rid ) {
ids [ i ] - > xid . id = combine_hashes ( h_domain , h_rid ) ;
ids [ i ] - > status = ID_MAPPED ;
}
}
done :
return nt_status ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS nss_hash_init ( struct nss_domain_entry * e )
{
2012-09-19 02:31:26 +04:00
return NT_STATUS_OK ;
2008-09-16 00:51:44 +04:00
}
/**********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS nss_hash_get_info ( struct nss_domain_entry * e ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * sid ,
2008-09-16 00:51:44 +04:00
TALLOC_CTX * ctx ,
2009-08-01 18:38:13 +04:00
const char * * homedir ,
const char * * shell ,
const char * * gecos ,
2008-09-16 00:51:44 +04:00
gid_t * p_gid )
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL ;
nt_status = nss_hash_init ( e ) ;
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
if ( ! homedir | | ! shell | | ! gecos ) {
nt_status = NT_STATUS_INVALID_PARAMETER ;
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
}
* homedir = talloc_strdup ( ctx , lp_template_homedir ( ) ) ;
BAIL_ON_PTR_NT_ERROR ( * homedir , nt_status ) ;
* shell = talloc_strdup ( ctx , lp_template_shell ( ) ) ;
BAIL_ON_PTR_NT_ERROR ( * shell , nt_status ) ;
* gecos = NULL ;
/* Initialize the gid so that the upper layer fills
in the proper Windows primary group */
if ( * p_gid ) {
* p_gid = ( gid_t ) - 1 ;
}
done :
return nt_status ;
}
/**********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS nss_hash_map_to_alias ( TALLOC_CTX * mem_ctx ,
2008-12-01 06:17:55 +03:00
struct nss_domain_entry * e ,
2008-09-16 00:51:44 +04:00
const char * name ,
char * * alias )
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL ;
const char * value ;
2008-12-01 06:17:55 +03:00
value = talloc_asprintf ( mem_ctx , " %s \\ %s " , e - > domain , name ) ;
2008-09-16 00:51:44 +04:00
BAIL_ON_PTR_NT_ERROR ( value , nt_status ) ;
nt_status = mapfile_lookup_key ( mem_ctx , value , alias ) ;
BAIL_ON_NTSTATUS_ERROR ( nt_status ) ;
done :
return nt_status ;
}
/**********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS nss_hash_map_from_alias ( TALLOC_CTX * mem_ctx ,
2008-12-01 06:17:55 +03:00
struct nss_domain_entry * e ,
2008-09-16 00:51:44 +04:00
const char * alias ,
char * * name )
{
return mapfile_lookup_value ( mem_ctx , alias , name ) ;
}
/**********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS nss_hash_close ( void )
{
return NT_STATUS_OK ;
}
/*********************************************************************
Dispatch Tables for IDMap and NssInfo Methods
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct idmap_methods hash_idmap_methods = {
. init = be_init ,
. unixids_to_sids = unixids_to_sids ,
. sids_to_unixids = sids_to_unixids ,
} ;
static struct nss_info_methods hash_nss_methods = {
. init = nss_hash_init ,
. get_nss_info = nss_hash_get_info ,
. map_to_alias = nss_hash_map_to_alias ,
. map_from_alias = nss_hash_map_from_alias ,
. close_fn = nss_hash_close
} ;
/**********************************************************************
Register with the idmap and idmap_nss subsystems . We have to protect
against the idmap and nss_info interfaces being in a half - registered
state .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-04-02 02:45:38 +04:00
NTSTATUS idmap_hash_init ( void )
2008-09-16 00:51:44 +04:00
{
static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL ;
static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL ;
if ( ! NT_STATUS_IS_OK ( idmap_status ) ) {
idmap_status = smb_register_idmap ( SMB_IDMAP_INTERFACE_VERSION ,
" hash " , & hash_idmap_methods ) ;
if ( ! NT_STATUS_IS_OK ( idmap_status ) ) {
DEBUG ( 0 , ( " Failed to register hash idmap plugin. \n " ) ) ;
return idmap_status ;
}
}
if ( ! NT_STATUS_IS_OK ( nss_status ) ) {
nss_status = smb_register_idmap_nss ( SMB_NSS_INFO_INTERFACE_VERSION ,
" hash " , & hash_nss_methods ) ;
if ( ! NT_STATUS_IS_OK ( nss_status ) ) {
DEBUG ( 0 , ( " Failed to register hash idmap nss plugin. \n " ) ) ;
return nss_status ;
}
}
return NT_STATUS_OK ;
}