2007-10-08 15:11:46 +04:00
/*
Unix SMB / CIFS implementation .
Async helpers for blocking functions
Copyright ( C ) Volker Lendecke 2005
Copyright ( C ) Gerald Carter 2006
2007-10-08 16:56:57 +04:00
Copyright ( C ) Simo Sorce 2007
2007-10-08 15:11:46 +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
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.h"
2020-09-11 13:16:00 +03:00
# include "../libcli/security/security.h"
# include "passdb/lookup_sid.h"
2021-01-03 23:53:49 +03:00
# include "lib/global_contexts.h"
2007-10-08 15:11:46 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2023-12-12 17:44:21 +03:00
static struct winbindd_child * static_idmap_child = NULL ;
2007-10-08 15:13:36 +04:00
2020-09-11 13:16:00 +03:00
/*
* Map idmap ranges to domain names , taken from smb . conf . This is
* stored in the parent winbind and used to assemble xids2sids / sids2xids calls
* into per - idmap - domain chunks .
*/
static struct wb_parent_idmap_config static_parent_idmap_config ;
2007-10-08 15:13:36 +04:00
struct winbindd_child * idmap_child ( void )
{
2023-12-12 17:44:21 +03:00
return static_idmap_child ;
2007-10-08 15:13:36 +04:00
}
2020-09-11 15:06:04 +03:00
bool is_idmap_child ( const struct winbindd_child * child )
{
2023-12-12 17:44:21 +03:00
if ( child = = static_idmap_child ) {
2020-09-11 15:06:04 +03:00
return true ;
}
return false ;
}
2020-09-11 15:06:04 +03:00
pid_t idmap_child_pid ( void )
{
2023-12-12 17:44:21 +03:00
return static_idmap_child - > pid ;
2020-09-11 15:06:04 +03:00
}
2018-02-14 15:24:54 +03:00
struct dcerpc_binding_handle * idmap_child_handle ( void )
{
2020-09-11 15:12:17 +03:00
/*
* The caller needs to use wb_parent_idmap_setup_send / recv
* before talking to the idmap child !
*/
SMB_ASSERT ( static_parent_idmap_config . num_doms > 0 ) ;
2023-12-12 17:44:21 +03:00
return static_idmap_child - > binding_handle ;
2018-02-14 15:24:54 +03:00
}
2020-09-11 16:42:42 +03:00
static void init_idmap_child_done ( struct tevent_req * subreq ) ;
2023-12-12 17:44:21 +03:00
NTSTATUS init_idmap_child ( TALLOC_CTX * mem_ctx )
2009-08-30 13:12:17 +04:00
{
2020-09-11 16:42:42 +03:00
struct tevent_req * subreq = NULL ;
2023-12-12 17:44:21 +03:00
if ( static_idmap_child ! = NULL ) {
DBG_ERR ( " idmap child already allocated \n " ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
static_idmap_child = talloc_zero ( mem_ctx , struct winbindd_child ) ;
if ( static_idmap_child = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
subreq = wb_parent_idmap_setup_send ( static_idmap_child ,
2020-09-11 16:42:42 +03:00
global_event_context ( ) ) ;
if ( subreq = = NULL ) {
/*
* This is only an optimization , so we ' re free to
* to ignore errors
*/
DBG_ERR ( " wb_parent_idmap_setup_send() failed \n " ) ;
2023-12-12 17:44:21 +03:00
return NT_STATUS_NO_MEMORY ;
2020-09-11 16:42:42 +03:00
}
tevent_req_set_callback ( subreq , init_idmap_child_done , NULL ) ;
DBG_DEBUG ( " wb_parent_idmap_setup_send() started \n " ) ;
2023-12-12 17:44:21 +03:00
return NT_STATUS_OK ;
2020-09-11 16:42:42 +03:00
}
static void init_idmap_child_done ( struct tevent_req * subreq )
{
const struct wb_parent_idmap_config * cfg = NULL ;
NTSTATUS status ;
status = wb_parent_idmap_setup_recv ( subreq , & cfg ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* This is only an optimization , so we ' re free to
* to ignore errors
*/
DBG_ERR ( " wb_parent_idmap_setup_recv() failed %s \n " ,
nt_errstr ( status ) ) ;
return ;
}
DBG_DEBUG ( " wb_parent_idmap_setup_recv() finished \n " ) ;
2009-08-30 13:12:17 +04:00
}
2020-09-11 13:16:00 +03:00
struct wb_parent_idmap_setup_state {
struct tevent_context * ev ;
struct wb_parent_idmap_config * cfg ;
size_t dom_idx ;
} ;
static void wb_parent_idmap_setup_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct wb_parent_idmap_setup_state * state =
tevent_req_data ( req ,
struct wb_parent_idmap_setup_state ) ;
if ( req_state = = TEVENT_REQ_DONE ) {
state - > cfg = NULL ;
return ;
}
if ( state - > cfg = = NULL ) {
return ;
}
state - > cfg - > num_doms = 0 ;
2022-06-21 19:19:16 +03:00
state - > cfg - > initialized = false ;
2020-09-11 13:16:00 +03:00
TALLOC_FREE ( state - > cfg - > doms ) ;
state - > cfg = NULL ;
}
static void wb_parent_idmap_setup_queue_wait_done ( struct tevent_req * subreq ) ;
static bool wb_parent_idmap_setup_scan_config ( const char * domname ,
void * private_data ) ;
static void wb_parent_idmap_setup_lookupname_next ( struct tevent_req * req ) ;
static void wb_parent_idmap_setup_lookupname_done ( struct tevent_req * subreq ) ;
struct tevent_req * wb_parent_idmap_setup_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev )
{
struct tevent_req * req = NULL ;
struct wb_parent_idmap_setup_state * state = NULL ;
struct tevent_req * subreq = NULL ;
req = tevent_req_create ( mem_ctx , & state ,
struct wb_parent_idmap_setup_state ) ;
if ( req = = NULL ) {
return NULL ;
}
* state = ( struct wb_parent_idmap_setup_state ) {
. ev = ev ,
. cfg = & static_parent_idmap_config ,
. dom_idx = 0 ,
} ;
2022-06-21 19:19:16 +03:00
if ( state - > cfg - > initialized ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2020-09-11 13:16:00 +03:00
if ( state - > cfg - > queue = = NULL ) {
state - > cfg - > queue = tevent_queue_create ( NULL ,
" wb_parent_idmap_config_queue " ) ;
if ( tevent_req_nomem ( state - > cfg - > queue , req ) ) {
return tevent_req_post ( req , ev ) ;
}
}
subreq = tevent_queue_wait_send ( state , state - > ev , state - > cfg - > queue ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
wb_parent_idmap_setup_queue_wait_done ,
req ) ;
return req ;
}
static void wb_parent_idmap_setup_queue_wait_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct wb_parent_idmap_setup_state * state =
tevent_req_data ( req ,
struct wb_parent_idmap_setup_state ) ;
bool ok ;
/*
* Note we don ' t call TALLOC_FREE ( subreq ) here in order to block the
* queue until tevent_req_received ( ) in wb_parent_idmap_setup_recv ( )
* will destroy it implicitly .
*/
ok = tevent_queue_wait_recv ( subreq ) ;
if ( ! ok ) {
DBG_ERR ( " tevent_queue_wait_recv() failed \n " ) ;
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return ;
}
if ( state - > cfg - > num_doms ! = 0 ) {
/*
* If we ' re not the first one we ' re done .
*/
tevent_req_done ( req ) ;
return ;
}
/*
* From this point we start changing state - > cfg ,
* which is & static_parent_idmap_config ,
* so we better setup a cleanup function
* to undo the changes on failure .
*/
tevent_req_set_cleanup_fn ( req , wb_parent_idmap_setup_cleanup ) ;
/*
* Put the passdb idmap domain first . We always need to try
* there first .
*/
state - > cfg - > doms = talloc_zero_array ( NULL ,
struct wb_parent_idmap_config_dom ,
1 ) ;
if ( tevent_req_nomem ( state - > cfg - > doms , req ) ) {
return ;
}
state - > cfg - > doms [ 0 ] . low_id = 0 ;
state - > cfg - > doms [ 0 ] . high_id = UINT_MAX ;
state - > cfg - > doms [ 0 ] . name = talloc_strdup ( state - > cfg - > doms ,
get_global_sam_name ( ) ) ;
if ( tevent_req_nomem ( state - > cfg - > doms [ 0 ] . name , req ) ) {
return ;
}
state - > cfg - > num_doms + = 1 ;
lp_scan_idmap_domains ( wb_parent_idmap_setup_scan_config , req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return ;
}
wb_parent_idmap_setup_lookupname_next ( req ) ;
}
static bool wb_parent_idmap_setup_scan_config ( const char * domname ,
void * private_data )
{
struct tevent_req * req =
talloc_get_type_abort ( private_data ,
struct tevent_req ) ;
struct wb_parent_idmap_setup_state * state =
tevent_req_data ( req ,
struct wb_parent_idmap_setup_state ) ;
struct wb_parent_idmap_config_dom * map = NULL ;
size_t i ;
const char * range ;
unsigned low_id , high_id ;
int ret ;
range = idmap_config_const_string ( domname , " range " , NULL ) ;
if ( range = = NULL ) {
DBG_DEBUG ( " No range for domain %s found \n " , domname ) ;
return false ;
}
ret = sscanf ( range , " %u - %u " , & low_id , & high_id ) ;
if ( ret ! = 2 ) {
DBG_DEBUG ( " Invalid range spec \" %s \" for domain %s \n " ,
range , domname ) ;
return false ;
}
if ( low_id > high_id ) {
DBG_DEBUG ( " Invalid range %u - %u for domain %s \n " ,
low_id , high_id , domname ) ;
return false ;
}
for ( i = 0 ; i < state - > cfg - > num_doms ; i + + ) {
if ( strequal ( domname , state - > cfg - > doms [ i ] . name ) ) {
map = & state - > cfg - > doms [ i ] ;
break ;
}
}
if ( map = = NULL ) {
struct wb_parent_idmap_config_dom * tmp ;
char * name ;
name = talloc_strdup ( state , domname ) ;
if ( name = = NULL ) {
DBG_ERR ( " talloc failed \n " ) ;
return false ;
}
tmp = talloc_realloc (
NULL , state - > cfg - > doms , struct wb_parent_idmap_config_dom ,
state - > cfg - > num_doms + 1 ) ;
if ( tmp = = NULL ) {
DBG_ERR ( " talloc failed \n " ) ;
return false ;
}
state - > cfg - > doms = tmp ;
map = & state - > cfg - > doms [ state - > cfg - > num_doms ] ;
state - > cfg - > num_doms + = 1 ;
ZERO_STRUCTP ( map ) ;
map - > name = talloc_move ( state - > cfg - > doms , & name ) ;
}
map - > low_id = low_id ;
map - > high_id = high_id ;
return false ;
}
static void wb_parent_idmap_setup_lookupname_next ( struct tevent_req * req )
{
struct wb_parent_idmap_setup_state * state =
tevent_req_data ( req ,
struct wb_parent_idmap_setup_state ) ;
struct wb_parent_idmap_config_dom * dom =
& state - > cfg - > doms [ state - > dom_idx ] ;
struct tevent_req * subreq = NULL ;
next_domain :
if ( state - > dom_idx = = state - > cfg - > num_doms ) {
2020-09-11 16:42:42 +03:00
/*
* We ' re done , so start the idmap child
*/
2023-12-12 17:44:21 +03:00
setup_child ( NULL , static_idmap_child , " log.winbindd " , " idmap " ) ;
2022-06-21 19:19:16 +03:00
static_parent_idmap_config . initialized = true ;
2020-09-11 13:16:00 +03:00
tevent_req_done ( req ) ;
return ;
}
if ( strequal ( dom - > name , " * " ) ) {
state - > dom_idx + + ;
goto next_domain ;
}
subreq = wb_lookupname_send ( state ,
state - > ev ,
dom - > name ,
dom - > name ,
" " ,
LOOKUP_NAME_NO_NSS ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
wb_parent_idmap_setup_lookupname_done ,
req ) ;
}
static void wb_parent_idmap_setup_lookupname_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct wb_parent_idmap_setup_state * state =
tevent_req_data ( req ,
struct wb_parent_idmap_setup_state ) ;
struct wb_parent_idmap_config_dom * dom =
& state - > cfg - > doms [ state - > dom_idx ] ;
enum lsa_SidType type ;
NTSTATUS status ;
status = wb_lookupname_recv ( subreq , & dom - > sid , & type ) ;
TALLOC_FREE ( subreq ) ;
2024-02-16 18:44:57 +03:00
if ( NT_STATUS_IS_OK ( status ) & & type = = SID_NAME_UNKNOWN ) {
status = NT_STATUS_NONE_MAPPED ;
}
2020-09-11 13:16:00 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " Lookup domain name '%s' failed '%s' \n " ,
dom - > name ,
nt_errstr ( status ) ) ;
state - > dom_idx + + ;
wb_parent_idmap_setup_lookupname_next ( req ) ;
return ;
}
if ( type ! = SID_NAME_DOMAIN ) {
struct dom_sid_buf buf ;
DBG_ERR ( " SID %s for idmap domain name '%s' "
" not a domain SID \n " ,
dom_sid_str_buf ( & dom - > sid , & buf ) ,
dom - > name ) ;
ZERO_STRUCT ( dom - > sid ) ;
}
state - > dom_idx + + ;
wb_parent_idmap_setup_lookupname_next ( req ) ;
return ;
}
NTSTATUS wb_parent_idmap_setup_recv ( struct tevent_req * req ,
const struct wb_parent_idmap_config * * _cfg )
{
const struct wb_parent_idmap_config * cfg = & static_parent_idmap_config ;
NTSTATUS status ;
* _cfg = NULL ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
/*
* Note state - > cfg is already set to NULL by
* wb_parent_idmap_setup_cleanup ( )
*/
* _cfg = cfg ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}