2015-08-20 18:07:47 +03:00
/*
* Unix SMB / CIFS implementation .
* async xids2sids
* Copyright ( C ) Volker Lendecke 2015
*
* 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"
# include "../libcli/security/security.h"
# include "idmap_cache.h"
# include "librpc/gen_ndr/ndr_winbind_c.h"
2016-01-12 23:21:17 +03:00
# include "librpc/gen_ndr/ndr_netlogon.h"
2017-09-25 14:25:57 +03:00
# include "passdb/lookup_sid.h"
2015-08-20 18:07:47 +03:00
2016-03-01 16:34:26 +03:00
struct wb_xids2sids_dom_state {
2016-01-12 23:21:17 +03:00
struct tevent_context * ev ;
2016-03-01 16:34:26 +03:00
struct unixid * all_xids ;
2019-02-25 16:55:00 +03:00
const bool * cached ;
2016-03-01 16:34:26 +03:00
size_t num_all_xids ;
struct dom_sid * all_sids ;
2020-09-11 13:31:13 +03:00
const struct wb_parent_idmap_config_dom * dom_map ;
2016-01-12 23:21:17 +03:00
bool tried_dclookup ;
2016-03-01 16:34:26 +03:00
size_t num_dom_xids ;
struct unixid * dom_xids ;
struct dom_sid * dom_sids ;
} ;
static void wb_xids2sids_dom_done ( struct tevent_req * subreq ) ;
2016-01-12 23:21:17 +03:00
static void wb_xids2sids_dom_gotdc ( struct tevent_req * subreq ) ;
2016-03-01 16:34:26 +03:00
static struct tevent_req * wb_xids2sids_dom_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
2020-09-11 13:31:13 +03:00
const struct wb_parent_idmap_config_dom * dom_map ,
2019-02-25 16:55:00 +03:00
struct unixid * xids ,
const bool * cached ,
size_t num_xids ,
struct dom_sid * sids )
2016-03-01 16:34:26 +03:00
{
struct tevent_req * req , * subreq ;
struct wb_xids2sids_dom_state * state ;
2020-09-11 13:35:09 +03:00
struct dcerpc_binding_handle * child_binding_handle = NULL ;
2016-03-01 16:34:26 +03:00
size_t i ;
req = tevent_req_create ( mem_ctx , & state ,
struct wb_xids2sids_dom_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2016-01-12 23:21:17 +03:00
state - > ev = ev ;
2016-03-01 16:34:26 +03:00
state - > all_xids = xids ;
2019-02-25 16:55:00 +03:00
state - > cached = cached ;
2016-03-01 16:34:26 +03:00
state - > num_all_xids = num_xids ;
state - > all_sids = sids ;
state - > dom_map = dom_map ;
state - > dom_xids = talloc_array ( state , struct unixid , num_xids ) ;
if ( tevent_req_nomem ( state - > dom_xids , req ) ) {
return tevent_req_post ( req , ev ) ;
}
state - > dom_sids = talloc_array ( state , struct dom_sid , num_xids ) ;
if ( tevent_req_nomem ( state - > dom_sids , req ) ) {
return tevent_req_post ( req , ev ) ;
}
for ( i = 0 ; i < num_xids ; i + + ) {
struct unixid id = state - > all_xids [ i ] ;
if ( ( id . id < dom_map - > low_id ) | | ( id . id > dom_map - > high_id ) ) {
/* out of range */
continue ;
}
2019-02-25 16:55:00 +03:00
if ( state - > cached [ i ] ) {
2019-04-12 17:56:45 +03:00
/* already found in cache */
continue ;
}
if ( ! is_null_sid ( & state - > all_sids [ i ] ) ) {
/* already mapped in a previously asked domain */
2016-03-01 16:34:26 +03:00
continue ;
}
state - > dom_xids [ state - > num_dom_xids + + ] = id ;
}
if ( state - > num_dom_xids = = 0 ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2020-09-11 13:35:09 +03:00
child_binding_handle = idmap_child_handle ( ) ;
2016-03-01 16:34:26 +03:00
subreq = dcerpc_wbint_UnixIDs2Sids_send (
2020-09-11 13:35:09 +03:00
state , ev , child_binding_handle , dom_map - > name , dom_map - > sid ,
2016-03-01 16:34:26 +03:00
state - > num_dom_xids , state - > dom_xids , state - > dom_sids ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , wb_xids2sids_dom_done , req ) ;
return req ;
}
static void wb_xids2sids_dom_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_xids2sids_dom_state * state = tevent_req_data (
req , struct wb_xids2sids_dom_state ) ;
2020-09-11 13:31:13 +03:00
const struct wb_parent_idmap_config_dom * dom_map = state - > dom_map ;
2016-03-01 16:34:26 +03:00
NTSTATUS status , result ;
size_t i ;
size_t dom_sid_idx ;
status = dcerpc_wbint_UnixIDs2Sids_recv ( subreq , state , & result ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2016-01-12 23:21:17 +03:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) & &
! state - > tried_dclookup ) {
subreq = wb_dsgetdcname_send (
state , state - > ev , state - > dom_map - > name , NULL , NULL ,
DS_RETURN_DNS_NAME ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , wb_xids2sids_dom_gotdc , req ) ;
return ;
}
2016-03-01 16:34:26 +03:00
if ( ! NT_STATUS_EQUAL ( result , NT_STATUS_NONE_MAPPED ) & &
tevent_req_nterror ( req , result ) ) {
return ;
}
dom_sid_idx = 0 ;
for ( i = 0 ; i < state - > num_all_xids ; i + + ) {
2019-02-21 20:39:46 +03:00
struct unixid * id = & state - > all_xids [ i ] ;
2016-03-01 16:34:26 +03:00
2019-02-21 20:39:46 +03:00
if ( ( id - > id < dom_map - > low_id ) | | ( id - > id > dom_map - > high_id ) ) {
2016-03-01 16:34:26 +03:00
/* out of range */
continue ;
}
2019-02-25 16:55:00 +03:00
if ( state - > cached [ i ] ) {
2019-04-12 17:56:45 +03:00
/* already found in cache */
continue ;
}
if ( ! is_null_sid ( & state - > all_sids [ i ] ) ) {
/* already mapped in a previously asked domain */
2016-03-01 16:34:26 +03:00
continue ;
}
2016-12-20 18:22:48 +03:00
sid_copy ( & state - > all_sids [ i ] , & state - > dom_sids [ dom_sid_idx ] ) ;
2019-02-21 20:40:20 +03:00
* id = state - > dom_xids [ dom_sid_idx ] ;
2016-12-20 18:22:48 +03:00
dom_sid_idx + = 1 ;
2016-03-01 16:34:26 +03:00
}
tevent_req_done ( req ) ;
}
2016-01-12 23:21:17 +03:00
static void wb_xids2sids_dom_gotdc ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_xids2sids_dom_state * state = tevent_req_data (
req , struct wb_xids2sids_dom_state ) ;
2020-09-11 13:35:09 +03:00
struct dcerpc_binding_handle * child_binding_handle = NULL ;
2016-01-12 23:21:17 +03:00
struct netr_DsRGetDCNameInfo * dcinfo ;
NTSTATUS status ;
status = wb_dsgetdcname_recv ( subreq , state , & dcinfo ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
state - > tried_dclookup = true ;
status = wb_dsgetdcname_gencache_set ( state - > dom_map - > name , dcinfo ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2020-09-11 13:35:09 +03:00
child_binding_handle = idmap_child_handle ( ) ;
2016-01-12 23:21:17 +03:00
subreq = dcerpc_wbint_UnixIDs2Sids_send (
2020-09-11 13:35:09 +03:00
state , state - > ev , child_binding_handle , state - > dom_map - > name ,
2017-09-25 16:39:39 +03:00
state - > dom_map - > sid , state - > num_dom_xids ,
state - > dom_xids , state - > dom_sids ) ;
2016-01-12 23:21:17 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , wb_xids2sids_dom_done , req ) ;
}
2016-03-01 16:34:26 +03:00
static NTSTATUS wb_xids2sids_dom_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2015-08-20 18:07:47 +03:00
struct wb_xids2sids_state {
2016-03-01 16:34:26 +03:00
struct tevent_context * ev ;
struct unixid * xids ;
size_t num_xids ;
2015-08-20 18:07:47 +03:00
struct dom_sid * sids ;
2019-02-22 13:00:00 +03:00
bool * cached ;
2016-03-01 16:34:26 +03:00
size_t dom_idx ;
2020-09-11 13:31:13 +03:00
const struct wb_parent_idmap_config * cfg ;
2015-08-20 18:07:47 +03:00
} ;
2020-09-11 13:31:13 +03:00
static void wb_xids2sids_idmap_setup_done ( struct tevent_req * subreq ) ;
2015-08-20 18:07:47 +03:00
static void wb_xids2sids_done ( struct tevent_req * subreq ) ;
struct tevent_req * wb_xids2sids_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
2019-02-22 18:29:07 +03:00
const struct unixid * xids ,
2015-08-20 18:07:47 +03:00
uint32_t num_xids )
{
struct tevent_req * req , * subreq ;
struct wb_xids2sids_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct wb_xids2sids_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2016-03-01 16:34:26 +03:00
state - > ev = ev ;
state - > num_xids = num_xids ;
2015-08-20 18:07:47 +03:00
2019-02-21 20:34:51 +03:00
state - > xids = talloc_array ( state , struct unixid , num_xids ) ;
if ( tevent_req_nomem ( state - > xids , req ) ) {
return tevent_req_post ( req , ev ) ;
}
memcpy ( state - > xids , xids , num_xids * sizeof ( struct unixid ) ) ;
2016-03-01 16:34:26 +03:00
state - > sids = talloc_zero_array ( state , struct dom_sid , num_xids ) ;
2015-08-20 18:07:47 +03:00
if ( tevent_req_nomem ( state - > sids , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2019-02-22 13:00:00 +03:00
state - > cached = talloc_zero_array ( state , bool , num_xids ) ;
if ( tevent_req_nomem ( state - > cached , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2016-12-27 13:19:17 +03:00
if ( winbindd_use_idmap_cache ( ) ) {
uint32_t i ;
for ( i = 0 ; i < num_xids ; i + + ) {
2019-02-26 14:46:39 +03:00
struct dom_sid sid = { 0 } ;
2019-02-26 14:52:28 +03:00
bool ok , expired = true ;
2016-12-27 13:19:17 +03:00
2019-02-26 16:34:56 +03:00
ok = idmap_cache_find_xid2sid (
& xids [ i ] , & sid , & expired ) ;
2016-12-27 13:19:17 +03:00
if ( ok & & ! expired ) {
2019-02-06 19:06:28 +03:00
struct dom_sid_buf buf ;
DBG_DEBUG ( " Found %cID in cache: %s \n " ,
xids [ i ] . type = = ID_TYPE_UID ? ' U ' : ' G ' ,
dom_sid_str_buf ( & sid , & buf ) ) ;
2016-12-27 13:19:17 +03:00
sid_copy ( & state - > sids [ i ] , & sid ) ;
2019-02-22 13:00:00 +03:00
state - > cached [ i ] = true ;
2016-12-27 13:19:17 +03:00
}
}
}
2020-09-11 13:31:13 +03:00
subreq = wb_parent_idmap_setup_send ( state , state - > ev ) ;
2017-09-25 14:25:57 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2020-09-11 13:31:13 +03:00
tevent_req_set_callback ( subreq , wb_xids2sids_idmap_setup_done , req ) ;
2017-09-25 14:25:57 +03:00
return req ;
}
2020-09-11 13:31:13 +03:00
static void wb_xids2sids_idmap_setup_done ( struct tevent_req * subreq )
2017-09-25 14:25:57 +03:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_xids2sids_state * state = tevent_req_data (
req , struct wb_xids2sids_state ) ;
NTSTATUS status ;
2020-09-11 13:31:13 +03:00
status = wb_parent_idmap_setup_recv ( subreq , & state - > cfg ) ;
2017-09-25 14:25:57 +03:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2020-09-11 13:31:13 +03:00
SMB_ASSERT ( state - > cfg - > num_doms > 0 ) ;
2016-03-01 16:34:26 +03:00
subreq = wb_xids2sids_dom_send (
2020-09-11 13:31:13 +03:00
state , state - > ev ,
& state - > cfg - > doms [ state - > dom_idx ] ,
2019-02-25 16:55:00 +03:00
state - > xids , state - > cached , state - > num_xids , state - > sids ) ;
2015-08-20 18:07:47 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2017-09-25 14:25:57 +03:00
return ;
2015-08-20 18:07:47 +03:00
}
tevent_req_set_callback ( subreq , wb_xids2sids_done , req ) ;
2017-09-25 14:25:57 +03:00
return ;
2015-08-20 18:07:47 +03:00
}
static void wb_xids2sids_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_xids2sids_state * state = tevent_req_data (
req , struct wb_xids2sids_state ) ;
2019-02-21 18:55:09 +03:00
size_t i ;
2016-03-01 16:34:26 +03:00
NTSTATUS status ;
2015-08-20 18:07:47 +03:00
2016-03-01 16:34:26 +03:00
status = wb_xids2sids_dom_recv ( subreq ) ;
2015-08-20 18:07:47 +03:00
TALLOC_FREE ( subreq ) ;
2016-03-01 16:34:26 +03:00
if ( tevent_req_nterror ( req , status ) ) {
2015-08-20 18:07:47 +03:00
return ;
}
2016-03-01 16:34:26 +03:00
state - > dom_idx + = 1 ;
2020-09-11 13:31:13 +03:00
if ( state - > dom_idx < state - > cfg - > num_doms ) {
const struct wb_parent_idmap_config_dom * dom_map =
& state - > cfg - > doms [ state - > dom_idx ] ;
2019-02-21 18:52:21 +03:00
subreq = wb_xids2sids_dom_send ( state ,
state - > ev ,
2020-09-11 13:31:13 +03:00
dom_map ,
2019-02-21 18:52:21 +03:00
state - > xids ,
2019-02-25 16:55:00 +03:00
state - > cached ,
2019-02-21 18:52:21 +03:00
state - > num_xids ,
state - > sids ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , wb_xids2sids_done , req ) ;
2016-03-01 16:34:26 +03:00
return ;
}
2019-02-21 18:55:09 +03:00
for ( i = 0 ; i < state - > num_xids ; i + + ) {
/*
* Prime the cache after an xid2sid call . It ' s important that we
* use the xid value returned from the backend for the xid value
* passed to idmap_cache_set_sid2unixid ( ) , not the input to
* wb_xids2sids_send : the input carries what was asked for ,
* e . g . a ID_TYPE_UID . The result from the backend something the
* idmap child possibly changed to ID_TYPE_BOTH .
*
* And of course If the value was from the cache don ' t update
* the cache .
*/
if ( state - > cached [ i ] ) {
continue ;
}
idmap_cache_set_sid2unixid ( & state - > sids [ i ] , & state - > xids [ i ] ) ;
}
2019-02-21 18:52:21 +03:00
tevent_req_done ( req ) ;
return ;
2015-08-20 18:07:47 +03:00
}
NTSTATUS wb_xids2sids_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct dom_sid * * sids )
{
struct wb_xids2sids_state * state = tevent_req_data (
req , struct wb_xids2sids_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
DEBUG ( 5 , ( " wb_sids_to_xids failed: %s \n " , nt_errstr ( status ) ) ) ;
return status ;
}
* sids = talloc_move ( mem_ctx , & state - > sids ) ;
return NT_STATUS_OK ;
}