2013-08-28 11:49:27 +04:00
/*
* idmap_autorid_tdb : This file contains common code used by
* idmap_autorid and net idmap autorid utilities . The common
* code provides functions for performing various operations
* on autorid . tdb
*
* Copyright ( C ) Christian Ambach , 2010 - 2012
* Copyright ( C ) Atul Kulkarni , 2013
* Copyright ( C ) Michael Adam , 2012 - 2013
*
* 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 "idmap_autorid_tdb.h"
2013-08-30 17:19:28 +04:00
# include "../libcli/security/dom_sid.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.h"
2013-08-28 11:49:27 +04:00
2013-08-30 19:31:16 +04:00
/**
* Build the database keystring for getting a range
* belonging to a domain sid and a range index .
*/
static void idmap_autorid_build_keystr ( const char * domsid ,
uint32_t domain_range_index ,
fstring keystr )
{
if ( domain_range_index > 0 ) {
2013-10-01 16:23:06 +04:00
fstr_sprintf ( keystr , " %s#% " PRIu32 ,
domsid , domain_range_index ) ;
2013-08-30 19:31:16 +04:00
} else {
fstrcpy ( keystr , domsid ) ;
}
}
2013-09-15 13:58:02 +04:00
static char * idmap_autorid_build_keystr_talloc ( TALLOC_CTX * mem_ctx ,
const char * domsid ,
uint32_t domain_range_index )
{
char * keystr ;
if ( domain_range_index > 0 ) {
keystr = talloc_asprintf ( mem_ctx , " %s#% " PRIu32 , domsid ,
domain_range_index ) ;
} else {
keystr = talloc_strdup ( mem_ctx , domsid ) ;
}
return keystr ;
}
2013-08-30 17:19:28 +04:00
static bool idmap_autorid_validate_sid ( const char * sid )
{
struct dom_sid ignore ;
if ( sid = = NULL ) {
return false ;
}
if ( strcmp ( sid , ALLOC_RANGE ) = = 0 ) {
return true ;
}
return dom_sid_parse ( sid , & ignore ) ;
}
struct idmap_autorid_addrange_ctx {
struct autorid_range_config * range ;
bool acquire ;
} ;
static NTSTATUS idmap_autorid_addrange_action ( struct db_context * db ,
2013-08-28 11:49:27 +04:00
void * private_data )
{
2013-08-30 17:19:28 +04:00
struct idmap_autorid_addrange_ctx * ctx ;
uint32_t requested_rangenum , stored_rangenum ;
struct autorid_range_config * range ;
bool acquire ;
2013-08-28 11:49:27 +04:00
NTSTATUS ret ;
2013-08-30 17:19:28 +04:00
uint32_t hwm ;
2013-08-28 11:49:27 +04:00
char * numstr ;
2016-12-05 18:31:56 +03:00
struct autorid_global_config globalcfg = { 0 } ;
2013-08-30 12:19:10 +04:00
fstring keystr ;
2013-08-30 17:19:28 +04:00
uint32_t increment ;
2013-09-10 15:35:56 +04:00
TALLOC_CTX * mem_ctx = NULL ;
2013-08-28 11:49:27 +04:00
2013-08-30 17:19:28 +04:00
ctx = ( struct idmap_autorid_addrange_ctx * ) private_data ;
range = ctx - > range ;
acquire = ctx - > acquire ;
if ( db = = NULL ) {
2023-08-07 07:51:21 +03:00
DEBUG ( 3 , ( " Invalid database argument: NULL \n " ) ) ;
2013-08-30 17:19:28 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
if ( range = = NULL ) {
2023-08-07 07:51:21 +03:00
DEBUG ( 3 , ( " Invalid range argument: NULL \n " ) ) ;
2013-08-30 17:19:28 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
2024-02-21 16:25:28 +03:00
requested_rangenum = range - > rangenum ;
2013-08-30 17:19:28 +04:00
DEBUG ( 10 , ( " Adding new range for domain %s "
" (domain_range_index=% " PRIu32 " ) \n " ,
range - > domsid , range - > domain_range_index ) ) ;
if ( ! idmap_autorid_validate_sid ( range - > domsid ) ) {
DEBUG ( 3 , ( " Invalid SID: %s \n " , range - > domsid ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
2013-08-28 11:49:27 +04:00
2013-08-30 19:31:16 +04:00
idmap_autorid_build_keystr ( range - > domsid , range - > domain_range_index ,
keystr ) ;
2013-08-30 12:19:10 +04:00
2013-08-30 17:19:28 +04:00
ret = dbwrap_fetch_uint32_bystring ( db , keystr , & stored_rangenum ) ;
2013-08-28 11:49:27 +04:00
if ( NT_STATUS_IS_OK ( ret ) ) {
/* entry is already present*/
2013-08-30 17:19:28 +04:00
if ( acquire ) {
DEBUG ( 10 , ( " domain range already allocated - "
" Not adding! \n " ) ) ;
2016-12-02 18:37:49 +03:00
2016-12-05 18:31:56 +03:00
ret = idmap_autorid_loadconfig ( db , & globalcfg ) ;
2016-12-02 18:37:49 +03:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 1 , ( " Fatal error while fetching "
" configuration: %s \n " ,
nt_errstr ( ret ) ) ) ;
goto error ;
}
range - > rangenum = stored_rangenum ;
2016-12-05 18:31:56 +03:00
range - > low_id = globalcfg . minvalue
+ range - > rangenum * globalcfg . rangesize ;
2016-12-02 18:37:49 +03:00
range - > high_id =
2016-12-05 18:31:56 +03:00
range - > low_id + globalcfg . rangesize - 1 ;
2016-12-02 18:37:49 +03:00
2013-08-30 17:19:28 +04:00
return NT_STATUS_OK ;
}
2013-08-28 11:49:27 +04:00
2013-08-30 17:19:28 +04:00
if ( stored_rangenum ! = requested_rangenum ) {
DEBUG ( 1 , ( " Error: requested rangenumber (%u) differs "
" from stored one (%u). \n " ,
requested_rangenum , stored_rangenum ) ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
DEBUG ( 10 , ( " Note: stored range agrees with requested "
" one - ok \n " ) ) ;
return NT_STATUS_OK ;
}
2013-08-28 11:49:27 +04:00
/* fetch the current HWM */
ret = dbwrap_fetch_uint32_bystring ( db , HWM , & hwm ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 1 , ( " Fatal error while fetching current "
" HWM value: %s \n " , nt_errstr ( ret ) ) ) ;
2013-09-10 15:35:56 +04:00
return NT_STATUS_INTERNAL_ERROR ;
2013-08-28 11:49:27 +04:00
}
2013-09-10 15:35:56 +04:00
mem_ctx = talloc_stackframe ( ) ;
2016-12-05 18:31:56 +03:00
ret = idmap_autorid_loadconfig ( db , & globalcfg ) ;
2013-08-30 12:05:49 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
2013-08-30 17:19:28 +04:00
DEBUG ( 1 , ( " Fatal error while fetching configuration: %s \n " ,
nt_errstr ( ret ) ) ) ;
goto error ;
}
if ( acquire ) {
/*
* automatically acquire the next range
*/
requested_rangenum = hwm ;
2013-08-30 12:05:49 +04:00
}
2016-12-05 18:31:56 +03:00
if ( requested_rangenum > = globalcfg . maxranges ) {
2023-02-27 14:14:41 +03:00
DBG_WARNING ( " Not enough ranges available: New range %u can't "
" be allocated. Consider increasing the range "
" [%u-%u] by %u. \n " ,
requested_rangenum ,
globalcfg . minvalue ,
globalcfg . minvalue +
( globalcfg . maxranges * globalcfg . rangesize ) ,
globalcfg . rangesize ) ;
2013-08-28 11:49:27 +04:00
ret = NT_STATUS_NO_MEMORY ;
goto error ;
}
2014-03-20 18:22:40 +04:00
/*
* Check that it is not yet taken .
* If the range is requested and < HWM , we need
* to check anyways , and otherwise , we also better
* check in order to prevent further corruption
* in case the db has been externally modified .
*/
numstr = talloc_asprintf ( mem_ctx , " %u " , requested_rangenum ) ;
if ( ! numstr ) {
2014-03-20 18:26:06 +04:00
DEBUG ( 1 , ( " Talloc failed! \n " ) ) ;
2014-03-20 18:22:40 +04:00
ret = NT_STATUS_NO_MEMORY ;
goto error ;
}
2013-08-30 17:19:28 +04:00
2014-03-20 18:22:40 +04:00
if ( dbwrap_exists ( db , string_term_tdb_data ( numstr ) ) ) {
DEBUG ( 1 , ( " Requested range '%s' is already in use. \n " , numstr ) ) ;
2013-09-12 09:37:17 +04:00
2014-03-20 18:22:40 +04:00
if ( requested_rangenum < hwm ) {
2013-09-12 09:37:17 +04:00
ret = NT_STATUS_INVALID_PARAMETER ;
2014-03-20 18:22:40 +04:00
} else {
ret = NT_STATUS_INTERNAL_DB_CORRUPTION ;
2013-09-12 09:37:17 +04:00
}
2014-03-20 18:22:40 +04:00
goto error ;
}
if ( requested_rangenum > = hwm ) {
2013-09-12 09:37:17 +04:00
/*
* requested or automatic range > = HWM :
* increment the HWM .
*/
/* HWM always contains current max range + 1 */
increment = requested_rangenum + 1 - hwm ;
/* increase the HWM */
ret = dbwrap_change_uint32_atomic_bystring ( db , HWM , & hwm ,
increment ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 1 , ( " Fatal error while incrementing the HWM "
" value in the database: %s \n " ,
nt_errstr ( ret ) ) ) ;
goto error ;
}
2013-08-28 11:49:27 +04:00
}
2013-09-12 09:37:17 +04:00
/*
* store away the new mapping in both directions
*/
2013-08-30 17:19:28 +04:00
ret = dbwrap_store_uint32_bystring ( db , keystr , requested_rangenum ) ;
2013-08-28 11:49:27 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 1 , ( " Fatal error while storing new "
2013-09-04 15:13:15 +04:00
" domain->range assignment: %s \n " , nt_errstr ( ret ) ) ) ;
2013-08-28 11:49:27 +04:00
goto error ;
}
2013-09-10 15:35:56 +04:00
numstr = talloc_asprintf ( mem_ctx , " %u " , requested_rangenum ) ;
2013-08-28 11:49:27 +04:00
if ( ! numstr ) {
ret = NT_STATUS_NO_MEMORY ;
goto error ;
}
ret = dbwrap_store_bystring ( db , numstr ,
2013-08-30 12:19:10 +04:00
string_term_tdb_data ( keystr ) , TDB_INSERT ) ;
2013-08-28 11:49:27 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
2013-09-04 15:13:15 +04:00
DEBUG ( 1 , ( " Fatal error while storing new "
" domain->range assignment: %s \n " , nt_errstr ( ret ) ) ) ;
2013-08-28 11:49:27 +04:00
goto error ;
}
2014-03-20 18:26:33 +04:00
DEBUG ( 5 , ( " %s new range #%d for domain %s "
" (domain_range_index=% " PRIu32 " ) \n " ,
( acquire ? " Acquired " : " Stored " ) ,
requested_rangenum , keystr ,
2013-08-28 11:49:27 +04:00
range - > domain_range_index ) ) ;
2013-08-30 17:19:28 +04:00
range - > rangenum = requested_rangenum ;
2013-08-28 11:49:27 +04:00
2016-12-05 18:31:56 +03:00
range - > low_id = globalcfg . minvalue
+ range - > rangenum * globalcfg . rangesize ;
range - > high_id = range - > low_id + globalcfg . rangesize - 1 ;
2013-08-30 14:48:39 +04:00
2013-09-10 15:35:56 +04:00
ret = NT_STATUS_OK ;
2013-08-28 11:49:27 +04:00
error :
2013-09-10 15:35:56 +04:00
talloc_free ( mem_ctx ) ;
2013-08-28 11:49:27 +04:00
return ret ;
2013-08-30 17:19:28 +04:00
}
2013-08-28 11:49:27 +04:00
2013-08-30 17:19:28 +04:00
static NTSTATUS idmap_autorid_addrange ( struct db_context * db ,
struct autorid_range_config * range ,
bool acquire )
{
NTSTATUS status ;
struct idmap_autorid_addrange_ctx ctx ;
ctx . acquire = acquire ;
ctx . range = range ;
status = dbwrap_trans_do ( db , idmap_autorid_addrange_action , & ctx ) ;
return status ;
2013-08-28 11:49:27 +04:00
}
2013-09-04 19:43:28 +04:00
NTSTATUS idmap_autorid_setrange ( struct db_context * db ,
const char * domsid ,
uint32_t domain_range_index ,
uint32_t rangenum )
{
NTSTATUS status ;
struct autorid_range_config range ;
ZERO_STRUCT ( range ) ;
fstrcpy ( range . domsid , domsid ) ;
range . domain_range_index = domain_range_index ;
range . rangenum = rangenum ;
status = idmap_autorid_addrange ( db , & range , false ) ;
return status ;
}
2016-12-02 18:11:24 +03:00
NTSTATUS idmap_autorid_acquire_range ( struct db_context * db ,
struct autorid_range_config * range )
2013-09-04 19:49:36 +04:00
{
return idmap_autorid_addrange ( db , range , true ) ;
}
2013-08-30 14:48:39 +04:00
static NTSTATUS idmap_autorid_getrange_int ( struct db_context * db ,
struct autorid_range_config * range )
2013-08-28 11:49:27 +04:00
{
2013-08-30 14:48:39 +04:00
NTSTATUS status = NT_STATUS_INVALID_PARAMETER ;
2016-12-05 18:31:56 +03:00
struct autorid_global_config globalcfg = { 0 } ;
2013-08-30 12:19:10 +04:00
fstring keystr ;
2013-08-28 11:49:27 +04:00
2013-08-30 14:48:39 +04:00
if ( db = = NULL | | range = = NULL ) {
DEBUG ( 3 , ( " Invalid arguments received \n " ) ) ;
goto done ;
}
2013-11-05 16:46:15 +04:00
if ( ! idmap_autorid_validate_sid ( range - > domsid ) ) {
DEBUG ( 3 , ( " Invalid SID: '%s' \n " , range - > domsid ) ) ;
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
2013-08-30 19:31:16 +04:00
idmap_autorid_build_keystr ( range - > domsid , range - > domain_range_index ,
keystr ) ;
2013-08-28 11:49:27 +04:00
2013-08-30 14:48:39 +04:00
DEBUG ( 10 , ( " reading domain range for key %s \n " , keystr ) ) ;
status = dbwrap_fetch_uint32_bystring ( db , keystr , & ( range - > rangenum ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2014-03-17 15:42:41 +04:00
DEBUG ( 1 , ( " Failed to read database record for key '%s': %s \n " ,
2013-09-15 15:07:21 +04:00
keystr , nt_errstr ( status ) ) ) ;
2013-08-30 14:48:39 +04:00
goto done ;
}
2016-12-05 18:31:56 +03:00
status = idmap_autorid_loadconfig ( db , & globalcfg ) ;
2013-08-30 14:48:39 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-08-07 07:51:21 +03:00
DEBUG ( 1 , ( " Failed to read global configuration \n " ) ) ;
2013-08-30 14:48:39 +04:00
goto done ;
}
2016-12-05 18:31:56 +03:00
range - > low_id = globalcfg . minvalue
+ range - > rangenum * globalcfg . rangesize ;
range - > high_id = range - > low_id + globalcfg . rangesize - 1 ;
2013-08-30 14:48:39 +04:00
done :
return status ;
}
2013-09-11 03:04:13 +04:00
NTSTATUS idmap_autorid_getrange ( struct db_context * db ,
const char * domsid ,
uint32_t domain_range_index ,
uint32_t * rangenum ,
uint32_t * low_id )
{
NTSTATUS status ;
struct autorid_range_config range ;
if ( rangenum = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
ZERO_STRUCT ( range ) ;
fstrcpy ( range . domsid , domsid ) ;
range . domain_range_index = domain_range_index ;
status = idmap_autorid_getrange_int ( db , & range ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
* rangenum = range . rangenum ;
if ( low_id ! = NULL ) {
* low_id = range . low_id ;
}
return NT_STATUS_OK ;
}
2013-08-30 14:48:39 +04:00
NTSTATUS idmap_autorid_get_domainrange ( struct db_context * db ,
struct autorid_range_config * range ,
bool read_only )
{
NTSTATUS ret ;
ret = idmap_autorid_getrange_int ( db , range ) ;
2013-08-28 11:49:27 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
2014-03-17 15:43:12 +04:00
DEBUG ( 10 , ( " Failed to read range config for '%s': %s \n " ,
range - > domsid , nt_errstr ( ret ) ) ) ;
2013-08-28 11:49:27 +04:00
if ( read_only ) {
2014-03-17 15:43:12 +04:00
DEBUG ( 10 , ( " Not allocating new range for '%s' because "
" read-only is enabled. \n " , range - > domsid ) ) ;
2013-08-28 11:49:27 +04:00
return NT_STATUS_NOT_FOUND ;
}
2013-08-30 17:19:28 +04:00
2013-09-04 19:49:36 +04:00
ret = idmap_autorid_acquire_range ( db , range ) ;
2013-08-28 11:49:27 +04:00
}
DEBUG ( 10 , ( " Using range #%d for domain %s "
" (domain_range_index=% " PRIu32 " , low_id=% " PRIu32 " ) \n " ,
range - > rangenum , range - > domsid , range - > domain_range_index ,
range - > low_id ) ) ;
return ret ;
}
/* initialize the given HWM to 0 if it does not exist yet */
2014-03-20 15:07:19 +04:00
static NTSTATUS idmap_autorid_init_hwm_action ( struct db_context * db ,
void * private_data )
{
NTSTATUS status ;
uint32_t hwmval ;
const char * hwm ;
hwm = ( char * ) private_data ;
status = dbwrap_fetch_uint32_bystring ( db , hwm , & hwmval ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " HWM (%s) already initialized in autorid database "
" (value % " PRIu32 " ). \n " , hwm , hwmval ) ) ;
return NT_STATUS_OK ;
}
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
DEBUG ( 0 , ( " Error fetching HWM (%s) from autorid "
" database: %s \n " , hwm , nt_errstr ( status ) ) ) ;
return status ;
}
status = dbwrap_trans_store_uint32_bystring ( db , hwm , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Error storing HWM (%s) in autorid database: %s \n " ,
hwm , nt_errstr ( status ) ) ) ;
return status ;
}
return NT_STATUS_OK ;
}
2013-08-28 11:49:27 +04:00
NTSTATUS idmap_autorid_init_hwm ( struct db_context * db , const char * hwm )
{
NTSTATUS status ;
uint32_t hwmval ;
status = dbwrap_fetch_uint32_bystring ( db , hwm , & hwmval ) ;
2014-03-20 14:23:05 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " HWM (%s) already initialized in autorid database "
" (value % " PRIu32 " ). \n " , hwm , hwmval ) ) ;
return NT_STATUS_OK ;
}
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
2013-08-28 11:49:27 +04:00
DEBUG ( 0 , ( " unable to fetch HWM (%s) from autorid "
" database: %s \n " , hwm , nt_errstr ( status ) ) ) ;
return status ;
}
2014-03-20 15:07:19 +04:00
status = dbwrap_trans_do ( db , idmap_autorid_init_hwm_action ,
2014-04-11 23:42:43 +04:00
discard_const ( hwm ) ) ;
2014-03-20 14:23:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Error initializing HWM (%s) in autorid database: "
" %s \n " , hwm , nt_errstr ( status ) ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
2014-03-20 02:43:35 +04:00
DEBUG ( 1 , ( " Initialized HWM (%s) in autorid database. \n " , hwm ) ) ;
2013-08-28 11:49:27 +04:00
return NT_STATUS_OK ;
}
2013-09-12 15:44:53 +04:00
/*
* Delete a domain # index < - > range mapping from the database .
* The mapping is specified by the sid and index .
* If force = = true , invalid mapping records are deleted as far
* as possible , otherwise they are left untouched .
*/
struct idmap_autorid_delete_range_by_sid_ctx {
const char * domsid ;
uint32_t domain_range_index ;
bool force ;
} ;
static NTSTATUS idmap_autorid_delete_range_by_sid_action ( struct db_context * db ,
void * private_data )
{
struct idmap_autorid_delete_range_by_sid_ctx * ctx =
( struct idmap_autorid_delete_range_by_sid_ctx * ) private_data ;
const char * domsid ;
uint32_t domain_range_index ;
uint32_t rangenum ;
char * keystr ;
char * range_keystr ;
TDB_DATA data ;
NTSTATUS status ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
bool is_valid_range_mapping = true ;
bool force ;
domsid = ctx - > domsid ;
domain_range_index = ctx - > domain_range_index ;
force = ctx - > force ;
keystr = idmap_autorid_build_keystr_talloc ( frame , domsid ,
domain_range_index ) ;
if ( keystr = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
status = dbwrap_fetch_uint32_bystring ( db , keystr , & rangenum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
range_keystr = talloc_asprintf ( frame , " % " PRIu32 , rangenum ) ;
if ( range_keystr = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
status = dbwrap_fetch_bystring ( db , frame , range_keystr , & data ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
DEBUG ( 1 , ( " Incomplete mapping %s -> %s: no backward mapping \n " ,
keystr , range_keystr ) ) ;
is_valid_range_mapping = false ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Error fetching reverse mapping for %s -> %s: %s \n " ,
keystr , range_keystr , nt_errstr ( status ) ) ) ;
goto done ;
} else if ( strncmp ( ( const char * ) data . dptr , keystr , strlen ( keystr ) )
! = 0 )
{
DEBUG ( 1 , ( " Invalid mapping: %s -> %s -> %s \n " ,
keystr , range_keystr , ( const char * ) data . dptr ) ) ;
is_valid_range_mapping = false ;
}
if ( ! is_valid_range_mapping & & ! force ) {
DEBUG ( 10 , ( " Not deleting invalid mapping, since not in force "
" mode. \n " ) ) ;
status = NT_STATUS_FILE_INVALID ;
goto done ;
}
status = dbwrap_delete_bystring ( db , keystr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Deletion of '%s' failed: %s \n " ,
keystr , nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! is_valid_range_mapping ) {
goto done ;
}
status = dbwrap_delete_bystring ( db , range_keystr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Deletion of '%s' failed: %s \n " ,
range_keystr , nt_errstr ( status ) ) ) ;
goto done ;
}
DEBUG ( 10 , ( " Deleted range mapping %s <--> %s \n " , keystr ,
range_keystr ) ) ;
done :
TALLOC_FREE ( frame ) ;
return status ;
}
NTSTATUS idmap_autorid_delete_range_by_sid ( struct db_context * db ,
const char * domsid ,
uint32_t domain_range_index ,
bool force )
{
NTSTATUS status ;
struct idmap_autorid_delete_range_by_sid_ctx ctx ;
ctx . domain_range_index = domain_range_index ;
ctx . domsid = domsid ;
ctx . force = force ;
status = dbwrap_trans_do ( db , idmap_autorid_delete_range_by_sid_action ,
& ctx ) ;
return status ;
}
2013-09-13 01:59:15 +04:00
/*
* Delete a domain # index < - > range mapping from the database .
* The mapping is specified by the range number .
* If force = = true , invalid mapping records are deleted as far
* as possible , otherwise they are left untouched .
*/
struct idmap_autorid_delete_range_by_num_ctx {
uint32_t rangenum ;
bool force ;
} ;
static NTSTATUS idmap_autorid_delete_range_by_num_action ( struct db_context * db ,
void * private_data )
{
struct idmap_autorid_delete_range_by_num_ctx * ctx =
( struct idmap_autorid_delete_range_by_num_ctx * ) private_data ;
uint32_t rangenum ;
2016-02-09 01:22:55 +03:00
char * keystr = NULL ;
2013-09-13 01:59:15 +04:00
char * range_keystr ;
TDB_DATA val ;
NTSTATUS status ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
bool is_valid_range_mapping = true ;
bool force ;
rangenum = ctx - > rangenum ;
force = ctx - > force ;
range_keystr = talloc_asprintf ( frame , " % " PRIu32 , rangenum ) ;
if ( range_keystr = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
ZERO_STRUCT ( val ) ;
status = dbwrap_fetch_bystring ( db , frame , range_keystr , & val ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
DEBUG ( 10 , ( " Did not find range '%s' in database. \n " ,
range_keystr ) ) ;
goto done ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 5 , ( " Error fetching rang key: %s \n " , nt_errstr ( status ) ) ) ;
goto done ;
}
if ( val . dptr = = NULL ) {
DEBUG ( 1 , ( " Invalid mapping: %s -> empty value \n " ,
range_keystr ) ) ;
is_valid_range_mapping = false ;
} else {
uint32_t reverse_rangenum = 0 ;
keystr = ( char * ) val . dptr ;
status = dbwrap_fetch_uint32_bystring ( db , keystr ,
& reverse_rangenum ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
DEBUG ( 1 , ( " Incomplete mapping %s -> %s: "
" no backward mapping \n " ,
range_keystr , keystr ) ) ;
is_valid_range_mapping = false ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Error fetching reverse mapping for "
" %s -> %s: %s \n " ,
range_keystr , keystr , nt_errstr ( status ) ) ) ;
goto done ;
} else if ( rangenum ! = reverse_rangenum ) {
is_valid_range_mapping = false ;
}
}
if ( ! is_valid_range_mapping & & ! force ) {
DEBUG ( 10 , ( " Not deleting invalid mapping, since not in force "
" mode. \n " ) ) ;
status = NT_STATUS_FILE_INVALID ;
goto done ;
}
status = dbwrap_delete_bystring ( db , range_keystr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Deletion of '%s' failed: %s \n " ,
range_keystr , nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! is_valid_range_mapping ) {
goto done ;
}
status = dbwrap_delete_bystring ( db , keystr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Deletion of '%s' failed: %s \n " ,
keystr , nt_errstr ( status ) ) ) ;
goto done ;
}
DEBUG ( 10 , ( " Deleted range mapping %s <--> %s \n " , range_keystr ,
keystr ) ) ;
done :
talloc_free ( frame ) ;
return status ;
}
NTSTATUS idmap_autorid_delete_range_by_num ( struct db_context * db ,
uint32_t rangenum ,
bool force )
{
NTSTATUS status ;
struct idmap_autorid_delete_range_by_num_ctx ctx ;
ctx . rangenum = rangenum ;
ctx . force = force ;
status = dbwrap_trans_do ( db , idmap_autorid_delete_range_by_num_action ,
& ctx ) ;
return status ;
}
2013-09-12 15:44:53 +04:00
2014-03-21 02:41:03 +04:00
/**
* Open and possibly create the database .
2013-08-28 11:49:27 +04:00
*/
2014-03-21 02:41:03 +04:00
NTSTATUS idmap_autorid_db_open ( const char * path ,
2013-08-28 11:49:27 +04:00
TALLOC_CTX * mem_ctx ,
struct db_context * * db )
{
if ( * db ! = NULL ) {
/* its already open */
return NT_STATUS_OK ;
}
/* Open idmap repository */
* db = db_open ( mem_ctx , path , 0 , TDB_DEFAULT , O_RDWR | O_CREAT , 0644 ,
2014-01-27 17:49:12 +04:00
DBWRAP_LOCK_ORDER_1 , DBWRAP_FLAG_NONE ) ;
2013-08-28 11:49:27 +04:00
if ( * db = = NULL ) {
DEBUG ( 0 , ( " Unable to open idmap_autorid database '%s' \n " , path ) ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
2014-04-23 20:19:09 +04:00
return NT_STATUS_OK ;
2014-03-21 02:41:03 +04:00
}
/**
* Initialize the high watermark records in the database .
*/
NTSTATUS idmap_autorid_init_hwms ( struct db_context * db )
{
NTSTATUS status ;
2013-08-28 11:49:27 +04:00
2014-03-21 02:41:03 +04:00
status = idmap_autorid_init_hwm ( db , HWM ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2013-08-28 11:49:27 +04:00
2014-03-21 02:41:03 +04:00
status = idmap_autorid_init_hwm ( db , ALLOC_HWM_UID ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2013-08-28 11:49:27 +04:00
2014-03-21 02:41:03 +04:00
status = idmap_autorid_init_hwm ( db , ALLOC_HWM_GID ) ;
2013-08-28 11:49:27 +04:00
return status ;
}
2014-03-21 02:41:03 +04:00
NTSTATUS idmap_autorid_db_init ( const char * path ,
TALLOC_CTX * mem_ctx ,
struct db_context * * db )
{
NTSTATUS status ;
status = idmap_autorid_db_open ( path , mem_ctx , db ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = idmap_autorid_init_hwms ( * db ) ;
return status ;
}
2013-08-28 16:20:13 +04:00
struct idmap_autorid_fetch_config_state {
TALLOC_CTX * mem_ctx ;
char * configstr ;
} ;
static void idmap_autorid_config_parser ( TDB_DATA key , TDB_DATA value ,
void * private_data )
{
struct idmap_autorid_fetch_config_state * state ;
state = ( struct idmap_autorid_fetch_config_state * ) private_data ;
/*
* strndup because we have non - nullterminated strings in the db
*/
state - > configstr = talloc_strndup (
state - > mem_ctx , ( const char * ) value . dptr , value . dsize ) ;
}
NTSTATUS idmap_autorid_getconfigstr ( struct db_context * db , TALLOC_CTX * mem_ctx ,
char * * result )
{
TDB_DATA key ;
NTSTATUS status ;
struct idmap_autorid_fetch_config_state state ;
if ( result = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
key = string_term_tdb_data ( CONFIGKEY ) ;
state . mem_ctx = mem_ctx ;
state . configstr = NULL ;
status = dbwrap_parse_record ( db , key , idmap_autorid_config_parser ,
& state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Error while retrieving config: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
if ( state . configstr = = NULL ) {
DEBUG ( 1 , ( " Error while retrieving config \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
DEBUG ( 5 , ( " found CONFIG: %s \n " , state . configstr ) ) ;
* result = state . configstr ;
return NT_STATUS_OK ;
}
2013-08-28 17:29:37 +04:00
bool idmap_autorid_parse_configstr ( const char * configstr ,
struct autorid_global_config * cfg )
{
unsigned long minvalue , rangesize , maxranges ;
if ( sscanf ( configstr ,
" minvalue:%lu rangesize:%lu maxranges:%lu " ,
& minvalue , & rangesize , & maxranges ) ! = 3 ) {
DEBUG ( 1 ,
2013-10-02 18:44:04 +04:00
( " Found invalid configuration data. "
" Creating new config \n " ) ) ;
2013-08-28 17:29:37 +04:00
return false ;
}
cfg - > minvalue = minvalue ;
cfg - > rangesize = rangesize ;
cfg - > maxranges = maxranges ;
return true ;
}
2013-09-10 20:07:15 +04:00
NTSTATUS idmap_autorid_loadconfig ( struct db_context * db ,
2016-12-05 18:31:56 +03:00
struct autorid_global_config * result )
2013-08-28 11:49:27 +04:00
{
2016-12-05 18:31:56 +03:00
struct autorid_global_config cfg = { 0 } ;
2013-08-28 11:49:27 +04:00
NTSTATUS status ;
2013-08-28 17:29:37 +04:00
bool ok ;
2013-08-28 16:32:19 +04:00
char * configstr = NULL ;
2013-08-28 11:49:27 +04:00
2013-09-10 20:07:15 +04:00
if ( result = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2016-12-05 18:31:56 +03:00
status = idmap_autorid_getconfigstr ( db , db , & configstr ) ;
2013-08-28 11:49:27 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2013-09-10 20:07:15 +04:00
return status ;
2013-08-28 11:49:27 +04:00
}
2016-12-05 18:31:56 +03:00
ok = idmap_autorid_parse_configstr ( configstr , & cfg ) ;
2016-12-05 18:29:06 +03:00
TALLOC_FREE ( configstr ) ;
2013-08-28 17:29:37 +04:00
if ( ! ok ) {
2013-09-10 20:07:15 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2013-08-28 11:49:27 +04:00
}
DEBUG ( 10 , ( " Loaded previously stored configuration "
" minvalue:%d rangesize:%d \n " ,
2016-12-05 18:31:56 +03:00
cfg . minvalue , cfg . rangesize ) ) ;
2013-08-28 11:49:27 +04:00
2013-09-10 20:07:15 +04:00
* result = cfg ;
2013-08-28 11:49:27 +04:00
2013-09-10 20:07:15 +04:00
return NT_STATUS_OK ;
2013-08-28 11:49:27 +04:00
}
NTSTATUS idmap_autorid_saveconfig ( struct db_context * db ,
struct autorid_global_config * cfg )
{
2016-12-05 18:31:56 +03:00
struct autorid_global_config storedconfig = { 0 } ;
2013-08-28 19:19:30 +04:00
NTSTATUS status = NT_STATUS_INVALID_PARAMETER ;
2013-08-28 11:49:27 +04:00
TDB_DATA data ;
char * cfgstr ;
2013-08-28 19:19:30 +04:00
uint32_t hwm ;
2013-09-10 20:27:46 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2013-08-28 19:19:30 +04:00
DEBUG ( 10 , ( " New configuration provided for storing is "
" minvalue:%d rangesize:%d maxranges:%d \n " ,
cfg - > minvalue , cfg - > rangesize , cfg - > maxranges ) ) ;
if ( cfg - > rangesize < 2000 ) {
DEBUG ( 1 , ( " autorid rangesize must be at least 2000 \n " ) ) ;
goto done ;
}
if ( cfg - > maxranges = = 0 ) {
DEBUG ( 1 , ( " An autorid maxranges value of 0 is invalid. "
" Must have at least one range available. \n " ) ) ;
goto done ;
}
2016-12-05 18:31:56 +03:00
status = idmap_autorid_loadconfig ( db , & storedconfig ) ;
2013-08-28 19:19:30 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
DEBUG ( 5 , ( " No configuration found. Storing initial "
" configuration. \n " ) ) ;
2016-12-05 18:31:56 +03:00
storedconfig = * cfg ;
2013-08-28 19:19:30 +04:00
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
2014-03-20 15:38:31 +04:00
DEBUG ( 1 , ( " Error loading configuration: %s \n " ,
nt_errstr ( status ) ) ) ;
2013-08-28 19:19:30 +04:00
goto done ;
}
/* did the minimum value or rangesize change? */
2016-12-05 18:31:56 +03:00
if ( ( storedconfig . minvalue ! = cfg - > minvalue ) | |
( storedconfig . rangesize ! = cfg - > rangesize ) )
2013-08-28 19:19:30 +04:00
{
DEBUG ( 1 , ( " New configuration values for rangesize or "
" minimum uid value conflict with previously "
" used values! Not storing new config. \n " ) ) ;
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
status = dbwrap_fetch_uint32_bystring ( db , HWM , & hwm ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Fatal error while fetching current "
" HWM value: %s \n " , nt_errstr ( status ) ) ) ;
status = NT_STATUS_INTERNAL_ERROR ;
goto done ;
}
/*
* has the highest uid value been reduced to setting that is not
* sufficient any more for already existing ranges ?
*/
if ( hwm > cfg - > maxranges ) {
DEBUG ( 1 , ( " New upper uid limit is too low to cover "
" existing mappings! Not storing new config. \n " ) ) ;
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
2013-08-28 11:49:27 +04:00
cfgstr =
2013-09-10 20:27:46 +04:00
talloc_asprintf ( frame ,
2013-08-28 11:49:27 +04:00
" minvalue:%u rangesize:%u maxranges:%u " ,
cfg - > minvalue , cfg - > rangesize , cfg - > maxranges ) ;
2013-09-10 20:27:46 +04:00
if ( cfgstr = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
2013-08-28 11:49:27 +04:00
}
data = string_tdb_data ( cfgstr ) ;
status = dbwrap_trans_store_bystring ( db , CONFIGKEY , data , TDB_REPLACE ) ;
2013-09-10 20:27:46 +04:00
done :
TALLOC_FREE ( frame ) ;
2013-08-28 11:49:27 +04:00
return status ;
}
2013-09-10 03:45:52 +04:00
NTSTATUS idmap_autorid_saveconfigstr ( struct db_context * db ,
const char * configstr )
{
bool ok ;
NTSTATUS status ;
struct autorid_global_config cfg ;
ok = idmap_autorid_parse_configstr ( configstr , & cfg ) ;
if ( ! ok ) {
return NT_STATUS_INVALID_PARAMETER ;
}
status = idmap_autorid_saveconfig ( db , & cfg ) ;
return status ;
}
2013-09-18 03:54:58 +04:00
/*
* iteration : Work on all range mappings for a given domain
*/
struct domain_range_visitor_ctx {
const char * domsid ;
NTSTATUS ( * fn ) ( struct db_context * db ,
const char * domsid ,
uint32_t index ,
uint32_t rangenum ,
void * private_data ) ;
void * private_data ;
int count ; /* number of records worked on */
} ;
static int idmap_autorid_visit_domain_range ( struct db_record * rec ,
void * private_data )
{
struct domain_range_visitor_ctx * vi ;
char * domsid ;
char * sep ;
uint32_t range_index = 0 ;
uint32_t rangenum = 0 ;
TDB_DATA key , value ;
NTSTATUS status ;
int ret = 0 ;
struct db_context * db ;
vi = talloc_get_type_abort ( private_data ,
struct domain_range_visitor_ctx ) ;
key = dbwrap_record_get_key ( rec ) ;
/*
* split string " <sid>[#<index>] " into sid string and index number
*/
domsid = ( char * ) key . dptr ;
DEBUG ( 10 , ( " idmap_autorid_visit_domain_range: visiting key '%s' \n " ,
domsid ) ) ;
sep = strrchr ( domsid , ' # ' ) ;
if ( sep ! = NULL ) {
char * index_str ;
* sep = ' \0 ' ;
index_str = sep + 1 ;
if ( sscanf ( index_str , " % " SCNu32 , & range_index ) ! = 1 ) {
DEBUG ( 10 , ( " Found separator '#' but '%s' is not a "
" valid range index. Skipping record \n " ,
index_str ) ) ;
goto done ;
}
}
if ( ! idmap_autorid_validate_sid ( domsid ) ) {
DEBUG ( 10 , ( " String '%s' is not a valid sid. "
" Skipping record. \n " , domsid ) ) ;
goto done ;
}
2013-10-02 02:39:07 +04:00
if ( ( vi - > domsid ! = NULL ) & & ( strcmp ( domsid , vi - > domsid ) ! = 0 ) ) {
2013-09-18 03:54:58 +04:00
DEBUG ( 10 , ( " key sid '%s' does not match requested sid '%s'. \n " ,
domsid , vi - > domsid ) ) ;
goto done ;
}
value = dbwrap_record_get_value ( rec ) ;
2013-10-18 18:26:41 +04:00
if ( value . dsize ! = sizeof ( uint32_t ) ) {
/* it might be a mapping of a well known sid */
DEBUG ( 10 , ( " value size %u != sizeof(uint32_t) for sid '%s', "
" skipping. \n " , ( unsigned ) value . dsize , vi - > domsid ) ) ;
goto done ;
}
2013-09-18 03:54:58 +04:00
rangenum = IVAL ( value . dptr , 0 ) ;
db = dbwrap_record_get_db ( rec ) ;
status = vi - > fn ( db , domsid , range_index , rangenum , vi - > private_data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = - 1 ;
goto done ;
}
vi - > count + + ;
ret = 0 ;
done :
return ret ;
}
static NTSTATUS idmap_autorid_iterate_domain_ranges_int ( struct db_context * db ,
const char * domsid ,
NTSTATUS ( * fn ) ( struct db_context * db ,
const char * domsid ,
uint32_t index ,
uint32_t rangnum ,
void * private_data ) ,
void * private_data ,
int * count ,
NTSTATUS ( * traverse ) ( struct db_context * db ,
int ( * f ) ( struct db_record * , void * ) ,
void * private_data ,
int * count ) )
{
NTSTATUS status ;
struct domain_range_visitor_ctx * vi ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( domsid = = NULL ) {
2013-10-02 02:39:07 +04:00
DEBUG ( 10 , ( " No sid provided, operating on all ranges \n " ) ) ;
2013-09-18 03:54:58 +04:00
}
if ( fn = = NULL ) {
DEBUG ( 1 , ( " Error: missing visitor callback \n " ) ) ;
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
vi = talloc_zero ( frame , struct domain_range_visitor_ctx ) ;
if ( vi = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
vi - > domsid = domsid ;
vi - > fn = fn ;
vi - > private_data = private_data ;
status = traverse ( db , idmap_autorid_visit_domain_range , vi , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
if ( count ! = NULL ) {
* count = vi - > count ;
}
done :
talloc_free ( frame ) ;
return status ;
}
NTSTATUS idmap_autorid_iterate_domain_ranges ( struct db_context * db ,
const char * domsid ,
NTSTATUS ( * fn ) ( struct db_context * db ,
const char * domsid ,
uint32_t index ,
uint32_t rangenum ,
void * private_data ) ,
void * private_data ,
int * count )
{
NTSTATUS status ;
status = idmap_autorid_iterate_domain_ranges_int ( db ,
domsid ,
fn ,
private_data ,
count ,
dbwrap_traverse ) ;
return status ;
}
NTSTATUS idmap_autorid_iterate_domain_ranges_read ( struct db_context * db ,
const char * domsid ,
NTSTATUS ( * fn ) ( struct db_context * db ,
const char * domsid ,
uint32_t index ,
uint32_t rangenum ,
void * count ) ,
void * private_data ,
int * count )
{
NTSTATUS status ;
status = idmap_autorid_iterate_domain_ranges_int ( db ,
domsid ,
fn ,
private_data ,
count ,
dbwrap_traverse_read ) ;
return status ;
}
2013-09-18 05:04:52 +04:00
/*
* Delete all ranges configured for a given domain
*/
struct delete_domain_ranges_visitor_ctx {
bool force ;
} ;
static NTSTATUS idmap_autorid_delete_domain_ranges_visitor (
struct db_context * db ,
const char * domsid ,
uint32_t domain_range_index ,
uint32_t rangenum ,
void * private_data )
{
struct delete_domain_ranges_visitor_ctx * ctx ;
NTSTATUS status ;
ctx = ( struct delete_domain_ranges_visitor_ctx * ) private_data ;
status = idmap_autorid_delete_range_by_sid (
db , domsid , domain_range_index , ctx - > force ) ;
return status ;
}
struct idmap_autorid_delete_domain_ranges_ctx {
const char * domsid ;
bool force ;
int count ; /* output: count records operated on */
} ;
static NTSTATUS idmap_autorid_delete_domain_ranges_action ( struct db_context * db ,
void * private_data )
{
struct idmap_autorid_delete_domain_ranges_ctx * ctx ;
struct delete_domain_ranges_visitor_ctx visitor_ctx ;
int count ;
NTSTATUS status ;
ctx = ( struct idmap_autorid_delete_domain_ranges_ctx * ) private_data ;
ZERO_STRUCT ( visitor_ctx ) ;
visitor_ctx . force = ctx - > force ;
status = idmap_autorid_iterate_domain_ranges ( db ,
ctx - > domsid ,
idmap_autorid_delete_domain_ranges_visitor ,
& visitor_ctx ,
& count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
ctx - > count = count ;
return NT_STATUS_OK ;
}
NTSTATUS idmap_autorid_delete_domain_ranges ( struct db_context * db ,
const char * domsid ,
bool force ,
int * count )
{
NTSTATUS status ;
struct idmap_autorid_delete_domain_ranges_ctx ctx ;
ZERO_STRUCT ( ctx ) ;
ctx . domsid = domsid ;
ctx . force = force ;
status = dbwrap_trans_do ( db , idmap_autorid_delete_domain_ranges_action ,
& ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
* count = ctx . count ;
return NT_STATUS_OK ;
}