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"
static NTSTATUS idmap_autorid_get_domainrange_action ( struct db_context * db ,
void * private_data )
{
NTSTATUS ret ;
uint32_t rangenum , hwm ;
char * numstr ;
struct autorid_range_config * range ;
range = ( struct autorid_range_config * ) private_data ;
ret = dbwrap_fetch_uint32_bystring ( db , range - > keystr ,
& ( range - > rangenum ) ) ;
if ( NT_STATUS_IS_OK ( ret ) ) {
/* entry is already present*/
return ret ;
}
DEBUG ( 10 , ( " Acquiring new range for domain %s "
" (domain_range_index=% " PRIu32 " ) \n " ,
range - > domsid , range - > domain_range_index ) ) ;
/* 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 ) ) ) ;
ret = NT_STATUS_INTERNAL_ERROR ;
goto error ;
}
/* do we have a range left? */
if ( hwm > = range - > globalcfg - > maxranges ) {
DEBUG ( 1 , ( " No more domain ranges available! \n " ) ) ;
ret = NT_STATUS_NO_MEMORY ;
goto error ;
}
/* increase the HWM */
ret = dbwrap_change_uint32_atomic_bystring ( db , HWM , & rangenum , 1 ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 1 , ( " Fatal error while fetching a new "
" domain range value! \n " ) ) ;
goto error ;
}
/* store away the new mapping in both directions */
ret = dbwrap_store_uint32_bystring ( db , range - > keystr , rangenum ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 1 , ( " Fatal error while storing new "
" domain->range assignment! \n " ) ) ;
goto error ;
}
numstr = talloc_asprintf ( db , " %u " , rangenum ) ;
if ( ! numstr ) {
ret = NT_STATUS_NO_MEMORY ;
goto error ;
}
ret = dbwrap_store_bystring ( db , numstr ,
string_term_tdb_data ( range - > keystr ) , TDB_INSERT ) ;
talloc_free ( numstr ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 1 , ( " Fatal error while storing "
" new domain->range assignment! \n " ) ) ;
goto error ;
}
DEBUG ( 5 , ( " Acquired new range #%d for domain %s "
" (domain_range_index=% " PRIu32 " ) \n " , rangenum , range - > keystr ,
range - > domain_range_index ) ) ;
range - > rangenum = rangenum ;
return NT_STATUS_OK ;
error :
return ret ;
}
NTSTATUS idmap_autorid_get_domainrange ( struct db_context * db ,
struct autorid_range_config * range ,
bool read_only )
{
NTSTATUS ret ;
/*
* try to find mapping without locking the database ,
* if it is not found create a mapping in a transaction unless
* read - only mode has been set
*/
if ( range - > domain_range_index > 0 ) {
snprintf ( range - > keystr , FSTRING_LEN , " %s#% " PRIu32 ,
range - > domsid , range - > domain_range_index ) ;
} else {
fstrcpy ( range - > keystr , range - > domsid ) ;
}
ret = dbwrap_fetch_uint32_bystring ( db , range - > keystr ,
& ( range - > rangenum ) ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
if ( read_only ) {
return NT_STATUS_NOT_FOUND ;
}
ret = dbwrap_trans_do ( db ,
idmap_autorid_get_domainrange_action , range ) ;
}
range - > low_id = range - > globalcfg - > minvalue
+ range - > rangenum * range - > globalcfg - > rangesize ;
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 */
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 ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
status = dbwrap_trans_store_int32_bystring ( db , hwm , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 ,
( " Unable to initialise HWM (%s) in autorid "
" database: %s \n " , hwm , nt_errstr ( status ) ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " unable to fetch HWM (%s) from autorid "
" database: %s \n " , hwm , nt_errstr ( status ) ) ) ;
return status ;
}
return NT_STATUS_OK ;
}
/*
* open and initialize the database which stores the ranges for the domains
*/
NTSTATUS idmap_autorid_db_init ( const char * path ,
TALLOC_CTX * mem_ctx ,
struct db_context * * db )
{
NTSTATUS status ;
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 ,
DBWRAP_LOCK_ORDER_1 ) ;
if ( * db = = NULL ) {
DEBUG ( 0 , ( " Unable to open idmap_autorid database '%s' \n " , path ) ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
/* Initialize high water mark for the currently used range to 0 */
status = idmap_autorid_init_hwm ( * db , HWM ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
status = idmap_autorid_init_hwm ( * db , ALLOC_HWM_UID ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
status = idmap_autorid_init_hwm ( * db , ALLOC_HWM_GID ) ;
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 ,
( " Found invalid configuration data "
" creating new config \n " ) ) ;
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 ,
TALLOC_CTX * mem_ctx ,
struct autorid_global_config * * result )
2013-08-28 11:49:27 +04:00
{
struct autorid_global_config * cfg ;
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 ;
}
2013-09-10 15:43:15 +04:00
status = idmap_autorid_getconfigstr ( db , mem_ctx , & 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
}
2013-09-10 15:43:15 +04:00
cfg = talloc_zero ( mem_ctx , struct autorid_global_config ) ;
2013-09-10 20:07:15 +04:00
if ( cfg = = NULL ) {
return NT_STATUS_NO_MEMORY ;
2013-08-28 11:49:27 +04:00
}
2013-08-28 17:29:37 +04:00
ok = idmap_autorid_parse_configstr ( configstr , cfg ) ;
if ( ! ok ) {
talloc_free ( cfg ) ;
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 " ,
cfg - > minvalue , cfg - > rangesize ) ) ;
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 )
{
2013-08-28 19:19:30 +04:00
struct autorid_global_config * storedconfig = NULL ;
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 ;
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 ;
}
status = idmap_autorid_loadconfig ( db , talloc_tos ( ) , & storedconfig ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
DEBUG ( 5 , ( " No configuration found. Storing initial "
" configuration. \n " ) ) ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
/* did the minimum value or rangesize change? */
if ( storedconfig & &
( ( storedconfig - > minvalue ! = cfg - > minvalue ) | |
( storedconfig - > rangesize ! = cfg - > rangesize ) ) )
{
DEBUG ( 1 , ( " New configuration values for rangesize or "
" minimum uid value conflict with previously "
" used values! Not storing new config. \n " ) ) ;
TALLOC_FREE ( storedconfig ) ;
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
TALLOC_FREE ( storedconfig ) ;
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 =
talloc_asprintf ( talloc_tos ( ) ,
" minvalue:%u rangesize:%u maxranges:%u " ,
cfg - > minvalue , cfg - > rangesize , cfg - > maxranges ) ;
if ( ! cfgstr ) {
return NT_STATUS_NO_MEMORY ;
}
data = string_tdb_data ( cfgstr ) ;
status = dbwrap_trans_store_bystring ( db , CONFIGKEY , data , TDB_REPLACE ) ;
2013-08-28 19:19:30 +04:00
TALLOC_FREE ( cfgstr ) ;
2013-08-28 11:49:27 +04:00
return status ;
}