2006-12-12 17:52:13 +03:00
/*
Unix SMB / CIFS implementation .
idmap TDB backend
Copyright ( C ) Tim Potter 2000
Copyright ( C ) Jim McDonough < jmcd @ us . ibm . com > 2003
Copyright ( C ) Jeremy Allison 2006
Copyright ( C ) Simo Sorce 2003 - 2006
2010-06-17 11:39:11 +04:00
Copyright ( C ) Michael Adam 2009 - 2010
2011-02-26 14:36:19 +03:00
2006-12-12 17:52:13 +03: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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-12-12 17:52:13 +03:00
( at your option ) any later version .
2011-02-26 14:36:19 +03:00
2006-12-12 17:52:13 +03:00
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 .
2011-02-26 14:36:19 +03:00
2006-12-12 17:52:13 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-12-12 17:52:13 +03:00
*/
# include "includes.h"
# include "winbindd.h"
2010-08-18 20:13:42 +04:00
# include "idmap.h"
2010-06-23 14:12:37 +04:00
# include "idmap_rw.h"
2010-08-18 20:59:23 +04:00
# include "dbwrap.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2006-12-12 17:52:13 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_IDMAP
2009-01-22 12:24:40 +03:00
/* idmap version determines auto-conversion - this is the database
structure version specifier . */
# define IDMAP_VERSION 2
2010-06-17 09:51:15 +04:00
struct idmap_tdb_context {
struct db_context * db ;
2010-06-23 14:12:37 +04:00
struct idmap_rw_ops * rw_ops ;
2010-06-17 09:51:15 +04:00
} ;
2006-12-12 17:52:13 +03:00
/* High water mark keys */
# define HWM_GROUP "GROUP HWM"
# define HWM_USER "USER HWM"
2008-12-16 23:14:36 +03:00
struct convert_fn_state {
struct db_context * db ;
bool failed ;
} ;
2006-12-12 17:52:13 +03:00
/*****************************************************************************
For idmap conversion : convert one record to new format
Ancient versions ( eg 2.2 .3 a ) of winbindd_idmap . tdb mapped DOMAINNAME / rid
instead of the SID .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-16 23:14:36 +03:00
static int convert_fn ( struct db_record * rec , void * private_data )
2006-12-12 17:52:13 +03:00
{
struct winbindd_domain * domain ;
char * p ;
2008-12-16 23:14:36 +03:00
NTSTATUS status ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2006-12-12 17:52:13 +03:00
uint32 rid ;
fstring keystr ;
fstring dom_name ;
TDB_DATA key2 ;
2008-12-16 23:14:36 +03:00
struct convert_fn_state * s = ( struct convert_fn_state * ) private_data ;
2006-12-12 17:52:13 +03:00
2008-12-16 23:14:36 +03:00
DEBUG ( 10 , ( " Converting %s \n " , ( const char * ) rec - > key . dptr ) ) ;
2006-12-12 17:52:13 +03:00
2008-12-16 23:14:36 +03:00
p = strchr ( ( const char * ) rec - > key . dptr , ' / ' ) ;
2006-12-12 17:52:13 +03:00
if ( ! p )
return 0 ;
* p = 0 ;
2008-12-16 23:14:36 +03:00
fstrcpy ( dom_name , ( const char * ) rec - > key . dptr ) ;
2006-12-12 17:52:13 +03:00
* p + + = ' / ' ;
domain = find_domain_from_name ( dom_name ) ;
if ( domain = = NULL ) {
/* We must delete the old record. */
DEBUG ( 0 , ( " Unable to find domain %s \n " , dom_name ) ) ;
2008-12-16 23:14:36 +03:00
DEBUG ( 0 , ( " deleting record %s \n " , ( const char * ) rec - > key . dptr ) ) ;
status = rec - > delete_rec ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Unable to delete record %s:%s \n " ,
( const char * ) rec - > key . dptr ,
nt_errstr ( status ) ) ) ;
s - > failed = true ;
2006-12-12 17:52:13 +03:00
return - 1 ;
}
return 0 ;
}
rid = atoi ( p ) ;
2010-01-10 19:39:27 +03:00
sid_compose ( & sid , & domain - > sid , rid ) ;
2006-12-12 17:52:13 +03:00
2007-12-16 00:47:30 +03:00
sid_to_fstring ( keystr , & sid ) ;
2007-03-27 15:01:37 +04:00
key2 = string_term_tdb_data ( keystr ) ;
2006-12-12 17:52:13 +03:00
2008-12-16 23:14:36 +03:00
status = dbwrap_store ( s - > db , key2 , rec - > value , TDB_INSERT ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Unable to add record %s:%s \n " ,
( const char * ) key2 . dptr ,
nt_errstr ( status ) ) ) ;
s - > failed = true ;
2006-12-12 17:52:13 +03:00
return - 1 ;
}
2008-12-16 23:14:36 +03:00
status = dbwrap_store ( s - > db , rec - > value , key2 , TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Unable to update record %s:%s \n " ,
( const char * ) rec - > value . dptr ,
nt_errstr ( status ) ) ) ;
s - > failed = true ;
2006-12-12 17:52:13 +03:00
return - 1 ;
}
2008-12-16 23:14:36 +03:00
status = rec - > delete_rec ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Unable to delete record %s:%s \n " ,
( const char * ) rec - > key . dptr ,
nt_errstr ( status ) ) ) ;
s - > failed = true ;
2006-12-12 17:52:13 +03:00
return - 1 ;
}
return 0 ;
}
/*****************************************************************************
Convert the idmap database from an older version .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-17 11:46:08 +04:00
static bool idmap_tdb_upgrade ( struct idmap_domain * dom , struct db_context * db )
2006-12-12 17:52:13 +03:00
{
int32 vers ;
2007-10-19 04:40:25 +04:00
bool bigendianheader ;
2008-12-16 23:14:36 +03:00
struct convert_fn_state s ;
2006-12-12 17:52:13 +03:00
2007-04-17 20:06:20 +04:00
DEBUG ( 0 , ( " Upgrading winbindd_idmap.tdb from an old version \n " ) ) ;
2008-12-16 23:14:36 +03:00
bigendianheader = ( db - > get_flags ( db ) & TDB_BIGENDIAN ) ? True : False ;
2006-12-12 17:52:13 +03:00
2008-12-16 23:14:36 +03:00
vers = dbwrap_fetch_int32 ( db , " IDMAP_VERSION " ) ;
2006-12-12 17:52:13 +03:00
if ( ( ( vers = = - 1 ) & & bigendianheader ) | | ( IREV ( vers ) = = IDMAP_VERSION ) ) {
/* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
/*
* high and low records were created on a
* big endian machine and will need byte - reversing .
*/
int32 wm ;
2008-12-16 23:14:36 +03:00
wm = dbwrap_fetch_int32 ( db , HWM_USER ) ;
2006-12-12 17:52:13 +03:00
if ( wm ! = - 1 ) {
wm = IREV ( wm ) ;
} else {
2010-06-17 11:46:08 +04:00
wm = dom - > low_id ;
2006-12-12 17:52:13 +03:00
}
2008-12-16 23:14:36 +03:00
if ( dbwrap_store_int32 ( db , HWM_USER , wm ) = = - 1 ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 0 , ( " Unable to byteswap user hwm in idmap database \n " ) ) ;
return False ;
}
2008-12-16 23:14:36 +03:00
wm = dbwrap_fetch_int32 ( db , HWM_GROUP ) ;
2006-12-12 17:52:13 +03:00
if ( wm ! = - 1 ) {
wm = IREV ( wm ) ;
} else {
2010-06-17 11:46:08 +04:00
wm = dom - > low_id ;
2006-12-12 17:52:13 +03:00
}
2008-12-16 23:14:36 +03:00
if ( dbwrap_store_int32 ( db , HWM_GROUP , wm ) = = - 1 ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 0 , ( " Unable to byteswap group hwm in idmap database \n " ) ) ;
return False ;
}
}
2008-12-16 23:14:36 +03:00
s . db = db ;
s . failed = false ;
2006-12-12 17:52:13 +03:00
/* the old format stored as DOMAIN/rid - now we store the SID direct */
2008-12-16 23:14:36 +03:00
db - > traverse ( db , convert_fn , & s ) ;
2006-12-12 17:52:13 +03:00
2008-12-16 23:14:36 +03:00
if ( s . failed ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 0 , ( " Problem during conversion \n " ) ) ;
return False ;
}
2008-12-16 23:14:36 +03:00
if ( dbwrap_store_int32 ( db , " IDMAP_VERSION " , IDMAP_VERSION ) = = - 1 ) {
2010-11-02 15:09:50 +03:00
DEBUG ( 0 , ( " Unable to store idmap version in database \n " ) ) ;
2006-12-12 17:52:13 +03:00
return False ;
}
return True ;
}
2010-06-17 10:11:19 +04:00
static NTSTATUS idmap_tdb_init_hwm ( struct idmap_domain * dom )
{
int ret ;
uint32_t low_uid ;
uint32_t low_gid ;
bool update_uid = false ;
bool update_gid = false ;
struct idmap_tdb_context * ctx ;
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
low_uid = dbwrap_fetch_int32 ( ctx - > db , HWM_USER ) ;
if ( low_uid = = - 1 | | low_uid < dom - > low_id ) {
update_uid = true ;
}
low_gid = dbwrap_fetch_int32 ( ctx - > db , HWM_GROUP ) ;
if ( low_gid = = - 1 | | low_gid < dom - > low_id ) {
update_gid = true ;
}
if ( ! update_uid & & ! update_gid ) {
return NT_STATUS_OK ;
}
if ( ctx - > db - > transaction_start ( ctx - > db ) ! = 0 ) {
DEBUG ( 0 , ( " Unable to start upgrade transaction! \n " ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
if ( update_uid ) {
ret = dbwrap_store_int32 ( ctx - > db , HWM_USER , dom - > low_id ) ;
if ( ret = = - 1 ) {
ctx - > db - > transaction_cancel ( ctx - > db ) ;
DEBUG ( 0 , ( " Unable to initialise user hwm in idmap "
" database \n " ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
}
if ( update_gid ) {
ret = dbwrap_store_int32 ( ctx - > db , HWM_GROUP , dom - > low_id ) ;
if ( ret = = - 1 ) {
ctx - > db - > transaction_cancel ( ctx - > db ) ;
DEBUG ( 0 , ( " Unable to initialise group hwm in idmap "
" database \n " ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
}
if ( ctx - > db - > transaction_commit ( ctx - > db ) ! = 0 ) {
DEBUG ( 0 , ( " Unable to commit upgrade transaction! \n " ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
return NT_STATUS_OK ;
}
2010-06-23 12:53:29 +04:00
static NTSTATUS idmap_tdb_open_db ( struct idmap_domain * dom )
2009-01-26 15:03:28 +03:00
{
NTSTATUS ret ;
2010-06-23 12:53:29 +04:00
TALLOC_CTX * mem_ctx ;
2009-01-26 15:03:28 +03:00
char * tdbfile = NULL ;
struct db_context * db = NULL ;
int32_t version ;
bool config_error = false ;
2010-06-23 12:53:29 +04:00
struct idmap_tdb_context * ctx ;
2009-01-26 15:03:28 +03:00
2010-06-23 12:53:29 +04:00
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
2006-12-12 17:52:13 +03:00
2010-06-17 11:35:52 +04:00
if ( ctx - > db ) {
/* it is already open */
return NT_STATUS_OK ;
}
2006-12-12 17:52:13 +03:00
/* use our own context here */
2010-06-23 12:53:29 +04:00
mem_ctx = talloc_stackframe ( ) ;
2006-12-12 17:52:13 +03:00
/* use the old database if present */
2009-01-26 15:17:49 +03:00
tdbfile = state_path ( " winbindd_idmap.tdb " ) ;
2006-12-12 17:52:13 +03:00
if ( ! tdbfile ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
ret = NT_STATUS_NO_MEMORY ;
goto done ;
}
DEBUG ( 10 , ( " Opening tdbfile %s \n " , tdbfile ) ) ;
/* Open idmap repository */
2010-06-23 12:53:29 +04:00
db = db_open ( mem_ctx , tdbfile , 0 , TDB_DEFAULT , O_RDWR | O_CREAT , 0644 ) ;
2008-12-16 23:14:36 +03:00
if ( ! db ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 0 , ( " Unable to open idmap database \n " ) ) ;
ret = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
/* check against earlier versions */
2008-12-16 23:14:36 +03:00
version = dbwrap_fetch_int32 ( db , " IDMAP_VERSION " ) ;
2006-12-12 17:52:13 +03:00
if ( version ! = IDMAP_VERSION ) {
2008-12-16 23:14:36 +03:00
if ( config_error ) {
DEBUG ( 0 , ( " Upgrade of IDMAP_VERSION from %d to %d is not "
" possible with incomplete configuration \n " ,
version , IDMAP_VERSION ) ) ;
ret = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
if ( db - > transaction_start ( db ) ! = 0 ) {
DEBUG ( 0 , ( " Unable to start upgrade transaction! \n " ) ) ;
ret = NT_STATUS_INTERNAL_DB_ERROR ;
goto done ;
}
2006-12-12 17:52:13 +03:00
2010-06-17 11:46:08 +04:00
if ( ! idmap_tdb_upgrade ( dom , db ) ) {
2008-12-16 23:14:36 +03:00
db - > transaction_cancel ( db ) ;
2009-07-29 16:43:14 +04:00
DEBUG ( 0 , ( " Unable to open idmap database, it's in an old format, and upgrade failed! \n " ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_INTERNAL_DB_ERROR ;
goto done ;
}
2008-12-16 23:14:36 +03:00
if ( db - > transaction_commit ( db ) ! = 0 ) {
DEBUG ( 0 , ( " Unable to commit upgrade transaction! \n " ) ) ;
ret = NT_STATUS_INTERNAL_DB_ERROR ;
2006-12-12 17:52:13 +03:00
goto done ;
}
}
2010-06-23 12:53:29 +04:00
ctx - > db = talloc_move ( ctx , & db ) ;
2010-06-17 10:12:43 +04:00
ret = idmap_tdb_init_hwm ( dom ) ;
2006-12-12 17:52:13 +03:00
done :
2010-06-23 12:53:29 +04:00
talloc_free ( mem_ctx ) ;
2006-12-12 17:52:13 +03:00
return ret ;
}
/**********************************************************************
IDMAP ALLOC TDB BACKEND
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-02-26 14:36:19 +03:00
2006-12-12 17:52:13 +03:00
/**********************************
Allocate a new id .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-16 11:19:21 +04:00
struct idmap_tdb_allocate_id_context {
const char * hwmkey ;
const char * hwmtype ;
uint32_t high_hwm ;
uint32_t hwm ;
} ;
static NTSTATUS idmap_tdb_allocate_id_action ( struct db_context * db ,
void * private_data )
2006-12-12 17:52:13 +03:00
{
2009-07-29 16:16:11 +04:00
NTSTATUS ret ;
2010-06-16 11:19:21 +04:00
struct idmap_tdb_allocate_id_context * state ;
uint32_t hwm ;
state = ( struct idmap_tdb_allocate_id_context * ) private_data ;
hwm = dbwrap_fetch_int32 ( db , state - > hwmkey ) ;
if ( hwm = = - 1 ) {
ret = NT_STATUS_INTERNAL_DB_ERROR ;
goto done ;
}
/* check it is in the range */
if ( hwm > state - > high_hwm ) {
DEBUG ( 1 , ( " Fatal Error: %s range full!! (max: %lu) \n " ,
state - > hwmtype , ( unsigned long ) state - > high_hwm ) ) ;
ret = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
/* fetch a new id and increment it */
ret = dbwrap_trans_change_uint32_atomic ( db , state - > hwmkey , & hwm , 1 ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 0 , ( " Fatal error while fetching a new %s value: %s \n ! " ,
state - > hwmtype , nt_errstr ( ret ) ) ) ;
goto done ;
}
/* recheck it is in the range */
if ( hwm > state - > high_hwm ) {
DEBUG ( 1 , ( " Fatal Error: %s range full!! (max: %lu) \n " ,
state - > hwmtype , ( unsigned long ) state - > high_hwm ) ) ;
ret = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
ret = NT_STATUS_OK ;
state - > hwm = hwm ;
done :
return ret ;
}
2010-06-17 10:16:05 +04:00
static NTSTATUS idmap_tdb_allocate_id ( struct idmap_domain * dom ,
struct unixid * xid )
2010-06-16 11:19:21 +04:00
{
2006-12-12 17:52:13 +03:00
const char * hwmkey ;
const char * hwmtype ;
uint32_t high_hwm ;
2010-06-16 11:19:21 +04:00
uint32_t hwm = 0 ;
NTSTATUS status ;
struct idmap_tdb_allocate_id_context state ;
2010-06-17 10:16:05 +04:00
struct idmap_tdb_context * ctx ;
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
2006-12-12 17:52:13 +03:00
/* Get current high water mark */
switch ( xid - > type ) {
case ID_TYPE_UID :
hwmkey = HWM_USER ;
hwmtype = " UID " ;
break ;
case ID_TYPE_GID :
hwmkey = HWM_GROUP ;
hwmtype = " GID " ;
break ;
default :
DEBUG ( 2 , ( " Invalid ID type (0x%x) \n " , xid - > type ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
2010-06-17 10:16:05 +04:00
high_hwm = dom - > high_id ;
2010-06-16 11:19:21 +04:00
state . hwm = hwm ;
state . high_hwm = high_hwm ;
state . hwmtype = hwmtype ;
state . hwmkey = hwmkey ;
2009-01-25 02:48:34 +03:00
2010-06-17 10:16:05 +04:00
status = dbwrap_trans_do ( ctx - > db , idmap_tdb_allocate_id_action ,
2010-06-16 11:19:21 +04:00
& state ) ;
2006-12-12 17:52:13 +03:00
2010-06-16 11:19:21 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
xid - > id = state . hwm ;
DEBUG ( 10 , ( " New %s = %d \n " , hwmtype , state . hwm ) ) ;
} else {
DEBUG ( 1 , ( " Error allocating a new %s \n " , hwmtype ) ) ;
2006-12-12 17:52:13 +03:00
}
2010-06-16 11:19:21 +04:00
return status ;
2006-12-12 17:52:13 +03:00
}
2010-06-16 11:26:17 +04:00
/**
* Allocate a new unix - ID .
* For now this is for the default idmap domain only .
* Should be extended later on .
*/
static NTSTATUS idmap_tdb_get_new_id ( struct idmap_domain * dom ,
struct unixid * id )
{
NTSTATUS ret ;
if ( ! strequal ( dom - > name , " * " ) ) {
DEBUG ( 3 , ( " idmap_tdb_get_new_id: "
" Refusing allocation of a new unixid for domain'%s'. "
" Currently only supported for the default "
" domain \" * \" . \n " ,
dom - > name ) ) ;
return NT_STATUS_NOT_IMPLEMENTED ;
}
2010-06-17 10:16:05 +04:00
ret = idmap_tdb_allocate_id ( dom , id ) ;
2010-06-16 11:26:17 +04:00
return ret ;
}
2006-12-12 17:52:13 +03:00
/**********************************************************************
IDMAP MAPPING TDB BACKEND
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*****************************
Initialise idmap database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-23 14:12:37 +04:00
static NTSTATUS idmap_tdb_set_mapping ( struct idmap_domain * dom ,
const struct id_map * map ) ;
2011-03-03 01:00:58 +03:00
static NTSTATUS idmap_tdb_db_init ( struct idmap_domain * dom )
2006-12-12 17:52:13 +03:00
{
NTSTATUS ret ;
struct idmap_tdb_context * ctx ;
2009-05-27 21:14:10 +04:00
DEBUG ( 10 , ( " idmap_tdb_db_init called for domain '%s' \n " , dom - > name ) ) ;
2010-06-22 11:01:32 +04:00
ctx = talloc_zero ( dom , struct idmap_tdb_context ) ;
2006-12-12 17:52:13 +03:00
if ( ! ctx ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-06-17 09:43:14 +04:00
/* load backend specific configuration here: */
#if 0
2009-05-27 21:12:28 +04:00
if ( strequal ( dom - > name , " * " ) ) {
} else {
2006-12-12 17:52:13 +03:00
}
2010-06-17 09:43:14 +04:00
# endif
2009-05-27 21:12:28 +04:00
2010-06-23 14:12:37 +04:00
ctx - > rw_ops = talloc_zero ( ctx , struct idmap_rw_ops ) ;
if ( ctx - > rw_ops = = NULL ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
ret = NT_STATUS_NO_MEMORY ;
goto failed ;
}
ctx - > rw_ops - > get_new_id = idmap_tdb_get_new_id ;
ctx - > rw_ops - > set_mapping = idmap_tdb_set_mapping ;
2010-06-23 12:53:29 +04:00
dom - > private_data = ctx ;
ret = idmap_tdb_open_db ( dom ) ;
2009-05-27 21:12:28 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
goto failed ;
}
2006-12-12 17:52:13 +03:00
return NT_STATUS_OK ;
failed :
talloc_free ( ctx ) ;
return ret ;
}
2010-06-17 10:43:11 +04:00
/**
* store a mapping in the database
*/
struct idmap_tdb_set_mapping_context {
const char * ksidstr ;
const char * kidstr ;
} ;
static NTSTATUS idmap_tdb_set_mapping_action ( struct db_context * db ,
void * private_data )
{
NTSTATUS ret ;
struct idmap_tdb_set_mapping_context * state ;
state = ( struct idmap_tdb_set_mapping_context * ) private_data ;
DEBUG ( 10 , ( " Storing %s <-> %s map \n " , state - > ksidstr , state - > kidstr ) ) ;
ret = dbwrap_store_bystring ( db , state - > ksidstr ,
string_term_tdb_data ( state - > kidstr ) ,
TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 0 , ( " Error storing SID -> ID (%s -> %s): %s \n " ,
state - > ksidstr , state - > kidstr , nt_errstr ( ret ) ) ) ;
goto done ;
}
ret = dbwrap_store_bystring ( db , state - > kidstr ,
string_term_tdb_data ( state - > ksidstr ) ,
TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 0 , ( " Error storing ID -> SID (%s -> %s): %s \n " ,
state - > kidstr , state - > ksidstr , nt_errstr ( ret ) ) ) ;
goto done ;
}
DEBUG ( 10 , ( " Stored %s <-> %s \n " , state - > ksidstr , state - > kidstr ) ) ;
ret = NT_STATUS_OK ;
done :
return ret ;
}
static NTSTATUS idmap_tdb_set_mapping ( struct idmap_domain * dom ,
const struct id_map * map )
{
struct idmap_tdb_context * ctx ;
NTSTATUS ret ;
char * ksidstr , * kidstr ;
struct idmap_tdb_set_mapping_context state ;
if ( ! map | | ! map - > sid ) {
return NT_STATUS_INVALID_PARAMETER ;
}
ksidstr = kidstr = NULL ;
/* TODO: should we filter a set_mapping using low/high filters ? */
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
switch ( map - > xid . type ) {
case ID_TYPE_UID :
kidstr = talloc_asprintf ( ctx , " UID %lu " ,
( unsigned long ) map - > xid . id ) ;
break ;
case ID_TYPE_GID :
kidstr = talloc_asprintf ( ctx , " GID %lu " ,
( unsigned long ) map - > xid . id ) ;
break ;
default :
DEBUG ( 2 , ( " INVALID unix ID type: 0x02%x \n " , map - > xid . type ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
if ( kidstr = = NULL ) {
DEBUG ( 0 , ( " ERROR: Out of memory! \n " ) ) ;
ret = NT_STATUS_NO_MEMORY ;
goto done ;
}
ksidstr = sid_string_talloc ( ctx , map - > sid ) ;
if ( ksidstr = = NULL ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
ret = NT_STATUS_NO_MEMORY ;
goto done ;
}
state . ksidstr = ksidstr ;
state . kidstr = kidstr ;
ret = dbwrap_trans_do ( ctx - > db , idmap_tdb_set_mapping_action , & state ) ;
done :
talloc_free ( ksidstr ) ;
talloc_free ( kidstr ) ;
return ret ;
}
2010-06-17 10:44:04 +04:00
/**
* Create a new mapping for an unmapped SID , also allocating a new ID .
* This should be run inside a transaction .
*
* TODO :
* Properly integrate this with multi domain idmap config :
* Currently , the allocator is default - config only .
*/
static NTSTATUS idmap_tdb_new_mapping ( struct idmap_domain * dom , struct id_map * map )
{
NTSTATUS ret ;
2010-06-23 14:02:31 +04:00
struct idmap_tdb_context * ctx ;
2010-06-17 10:44:04 +04:00
2010-06-23 14:02:31 +04:00
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
2010-06-17 10:44:04 +04:00
2010-06-23 14:02:31 +04:00
ret = idmap_rw_new_mapping ( dom , ctx - > rw_ops , map ) ;
2010-06-17 10:44:04 +04:00
return ret ;
}
2006-12-12 17:52:13 +03:00
/**********************************
Single id to sid lookup function .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-17 09:32:12 +04:00
static NTSTATUS idmap_tdb_id_to_sid ( struct idmap_domain * dom , struct id_map * map )
2006-12-12 17:52:13 +03:00
{
NTSTATUS ret ;
2007-03-27 15:01:37 +04:00
TDB_DATA data ;
char * keystr ;
2010-06-17 09:32:12 +04:00
struct idmap_tdb_context * ctx ;
2006-12-12 17:52:13 +03:00
2010-06-17 09:32:12 +04:00
if ( ! dom | | ! map ) {
2006-12-12 17:52:13 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
2010-06-17 09:32:12 +04:00
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
2006-12-12 17:52:13 +03:00
/* apply filters before checking */
2010-06-17 09:42:00 +04:00
if ( ! idmap_unix_id_is_in_range ( map - > xid . id , dom ) ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 5 , ( " Requested id (%u) out of range (%u - %u). Filtered! \n " ,
2010-06-17 09:42:00 +04:00
map - > xid . id , dom - > low_id , dom - > high_id ) ) ;
2006-12-12 17:52:13 +03:00
return NT_STATUS_NONE_MAPPED ;
}
switch ( map - > xid . type ) {
case ID_TYPE_UID :
2007-03-27 15:01:37 +04:00
keystr = talloc_asprintf ( ctx , " UID %lu " , ( unsigned long ) map - > xid . id ) ;
2006-12-12 17:52:13 +03:00
break ;
2011-02-26 14:36:19 +03:00
2006-12-12 17:52:13 +03:00
case ID_TYPE_GID :
2007-03-27 15:01:37 +04:00
keystr = talloc_asprintf ( ctx , " GID %lu " , ( unsigned long ) map - > xid . id ) ;
2006-12-12 17:52:13 +03:00
break ;
default :
DEBUG ( 2 , ( " INVALID unix ID type: 0x02%x \n " , map - > xid . type ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
/* final SAFE_FREE safe */
data . dptr = NULL ;
2007-03-27 15:01:37 +04:00
if ( keystr = = NULL ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
ret = NT_STATUS_NO_MEMORY ;
goto done ;
}
2007-03-27 15:01:37 +04:00
DEBUG ( 10 , ( " Fetching record %s \n " , keystr ) ) ;
2006-12-12 17:52:13 +03:00
/* Check if the mapping exists */
2008-12-16 23:14:36 +03:00
data = dbwrap_fetch_bystring ( ctx - > db , NULL , keystr ) ;
2006-12-12 17:52:13 +03:00
if ( ! data . dptr ) {
2007-03-27 15:01:37 +04:00
DEBUG ( 10 , ( " Record %s not found \n " , keystr ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_NONE_MAPPED ;
goto done ;
}
2011-02-26 14:36:19 +03:00
2007-03-29 13:35:51 +04:00
if ( ! string_to_sid ( map - > sid , ( const char * ) data . dptr ) ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 10 , ( " INVALID SID (%s) in record %s \n " ,
2007-03-29 13:35:51 +04:00
( const char * ) data . dptr , keystr ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_INTERNAL_DB_ERROR ;
goto done ;
}
2007-03-29 13:35:51 +04:00
DEBUG ( 10 , ( " Found record %s -> %s \n " , keystr , ( const char * ) data . dptr ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_OK ;
done :
2008-12-16 23:14:36 +03:00
talloc_free ( data . dptr ) ;
2007-03-27 15:01:37 +04:00
talloc_free ( keystr ) ;
2006-12-12 17:52:13 +03:00
return ret ;
}
/**********************************
Single sid to id lookup function .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-17 09:35:28 +04:00
static NTSTATUS idmap_tdb_sid_to_id ( struct idmap_domain * dom , struct id_map * map )
2006-12-12 17:52:13 +03:00
{
NTSTATUS ret ;
2007-03-27 15:01:37 +04:00
TDB_DATA data ;
char * keystr ;
2006-12-12 17:52:13 +03:00
unsigned long rec_id = 0 ;
2010-06-17 09:35:28 +04:00
struct idmap_tdb_context * ctx ;
2009-01-23 02:52:28 +03:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2006-12-12 17:52:13 +03:00
2010-06-17 09:35:28 +04:00
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
2009-01-23 02:52:28 +03:00
keystr = sid_string_talloc ( tmp_ctx , map - > sid ) ;
if ( keystr = = NULL ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
ret = NT_STATUS_NO_MEMORY ;
goto done ;
}
2007-03-27 15:01:37 +04:00
DEBUG ( 10 , ( " Fetching record %s \n " , keystr ) ) ;
2006-12-12 17:52:13 +03:00
/* Check if sid is present in database */
2009-01-23 02:52:28 +03:00
data = dbwrap_fetch_bystring ( ctx - > db , tmp_ctx , keystr ) ;
2006-12-12 17:52:13 +03:00
if ( ! data . dptr ) {
2007-03-27 15:01:37 +04:00
DEBUG ( 10 , ( " Record %s not found \n " , keystr ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_NONE_MAPPED ;
goto done ;
}
/* What type of record is this ? */
2007-03-29 13:35:51 +04:00
if ( sscanf ( ( const char * ) data . dptr , " UID %lu " , & rec_id ) = = 1 ) { /* Try a UID record. */
2006-12-12 17:52:13 +03:00
map - > xid . id = rec_id ;
map - > xid . type = ID_TYPE_UID ;
2007-03-29 13:35:51 +04:00
DEBUG ( 10 , ( " Found uid record %s -> %s \n " , keystr , ( const char * ) data . dptr ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_OK ;
2007-03-29 13:35:51 +04:00
} else if ( sscanf ( ( const char * ) data . dptr , " GID %lu " , & rec_id ) = = 1 ) { /* Try a GID record. */
2006-12-12 17:52:13 +03:00
map - > xid . id = rec_id ;
map - > xid . type = ID_TYPE_GID ;
2007-03-29 13:35:51 +04:00
DEBUG ( 10 , ( " Found gid record %s -> %s \n " , keystr , ( const char * ) data . dptr ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_OK ;
} else { /* Unknown record type ! */
2007-03-29 13:35:51 +04:00
DEBUG ( 2 , ( " Found INVALID record %s -> %s \n " , keystr , ( const char * ) data . dptr ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_INTERNAL_DB_ERROR ;
2010-05-17 12:39:00 +04:00
goto done ;
2006-12-12 17:52:13 +03:00
}
/* apply filters before returning result */
2010-06-17 09:42:00 +04:00
if ( ! idmap_unix_id_is_in_range ( map - > xid . id , dom ) ) {
2006-12-12 17:52:13 +03:00
DEBUG ( 5 , ( " Requested id (%u) out of range (%u - %u). Filtered! \n " ,
2010-06-17 09:42:00 +04:00
map - > xid . id , dom - > low_id , dom - > high_id ) ) ;
2006-12-12 17:52:13 +03:00
ret = NT_STATUS_NONE_MAPPED ;
}
done :
2009-01-23 02:52:28 +03:00
talloc_free ( tmp_ctx ) ;
2006-12-12 17:52:13 +03:00
return ret ;
}
/**********************************
lookup a set of unix ids .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS idmap_tdb_unixids_to_sids ( struct idmap_domain * dom , struct id_map * * ids )
{
NTSTATUS ret ;
int i ;
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
2006-12-12 17:52:13 +03:00
for ( i = 0 ; ids [ i ] ; i + + ) {
2010-06-17 09:32:12 +04:00
ret = idmap_tdb_id_to_sid ( dom , ids [ i ] ) ;
2006-12-12 17:52:13 +03:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
/* if it is just a failed mapping continue */
if ( NT_STATUS_EQUAL ( ret , NT_STATUS_NONE_MAPPED ) ) {
/* make sure it is marked as unmapped */
2007-01-14 20:58:24 +03:00
ids [ i ] - > status = ID_UNMAPPED ;
2006-12-12 17:52:13 +03:00
continue ;
}
2011-02-26 14:36:19 +03:00
2006-12-12 17:52:13 +03:00
/* some fatal error occurred, return immediately */
goto done ;
}
/* all ok, id is mapped */
2007-01-14 20:58:24 +03:00
ids [ i ] - > status = ID_MAPPED ;
2006-12-12 17:52:13 +03:00
}
ret = NT_STATUS_OK ;
done :
return ret ;
}
/**********************************
lookup a set of sids .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-17 10:53:54 +04:00
struct idmap_tdb_sids_to_unixids_context {
struct idmap_domain * dom ;
struct id_map * * ids ;
bool allocate_unmapped ;
} ;
static NTSTATUS idmap_tdb_sids_to_unixids_action ( struct db_context * db ,
void * private_data )
{
struct idmap_tdb_sids_to_unixids_context * state ;
int i ;
2010-08-19 16:01:47 +04:00
NTSTATUS ret = NT_STATUS_OK ;
2010-06-17 10:53:54 +04:00
state = ( struct idmap_tdb_sids_to_unixids_context * ) private_data ;
DEBUG ( 10 , ( " idmap_tdb_sids_to_unixids_action: "
" domain: [%s], allocate: %s \n " ,
state - > dom - > name ,
state - > allocate_unmapped ? " yes " : " no " ) ) ;
for ( i = 0 ; state - > ids [ i ] ; i + + ) {
if ( ( state - > ids [ i ] - > status = = ID_UNKNOWN ) | |
/* retry if we could not map in previous run: */
( state - > ids [ i ] - > status = = ID_UNMAPPED ) )
{
NTSTATUS ret2 ;
ret2 = idmap_tdb_sid_to_id ( state - > dom , state - > ids [ i ] ) ;
if ( ! NT_STATUS_IS_OK ( ret2 ) ) {
/* if it is just a failed mapping, continue */
if ( NT_STATUS_EQUAL ( ret2 , NT_STATUS_NONE_MAPPED ) ) {
/* make sure it is marked as unmapped */
state - > ids [ i ] - > status = ID_UNMAPPED ;
ret = STATUS_SOME_UNMAPPED ;
} else {
/* some fatal error occurred, return immediately */
ret = ret2 ;
goto done ;
}
} else {
/* all ok, id is mapped */
state - > ids [ i ] - > status = ID_MAPPED ;
}
}
if ( ( state - > ids [ i ] - > status = = ID_UNMAPPED ) & &
state - > allocate_unmapped )
{
ret = idmap_tdb_new_mapping ( state - > dom , state - > ids [ i ] ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
goto done ;
}
}
}
done :
return ret ;
}
2006-12-12 17:52:13 +03:00
static NTSTATUS idmap_tdb_sids_to_unixids ( struct idmap_domain * dom , struct id_map * * ids )
{
struct idmap_tdb_context * ctx ;
NTSTATUS ret ;
int i ;
2010-06-17 10:53:54 +04:00
struct idmap_tdb_sids_to_unixids_context state ;
2006-12-12 17:52:13 +03:00
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
2006-12-12 17:52:13 +03:00
ctx = talloc_get_type ( dom - > private_data , struct idmap_tdb_context ) ;
2010-06-17 10:53:54 +04:00
state . dom = dom ;
state . ids = ids ;
state . allocate_unmapped = false ;
2006-12-12 17:52:13 +03:00
2010-06-17 10:53:54 +04:00
ret = idmap_tdb_sids_to_unixids_action ( ctx - > db , & state ) ;
2006-12-12 17:52:13 +03:00
2010-06-17 10:53:54 +04:00
if ( NT_STATUS_EQUAL ( ret , STATUS_SOME_UNMAPPED ) & & ! dom - > read_only ) {
state . allocate_unmapped = true ;
ret = dbwrap_trans_do ( ctx - > db ,
idmap_tdb_sids_to_unixids_action ,
& state ) ;
2006-12-12 17:52:13 +03:00
}
return ret ;
}
2010-06-17 10:53:54 +04:00
2006-12-12 17:52:13 +03:00
/**********************************
Close the idmap tdb instance
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct idmap_methods db_methods = {
. init = idmap_tdb_db_init ,
. unixids_to_sids = idmap_tdb_unixids_to_sids ,
. sids_to_unixids = idmap_tdb_sids_to_unixids ,
2010-06-22 16:41:31 +04:00
. allocate_id = idmap_tdb_get_new_id ,
2006-12-12 17:52:13 +03:00
} ;
NTSTATUS idmap_tdb_init ( void )
{
2008-07-13 14:07:40 +04:00
DEBUG ( 10 , ( " calling idmap_tdb_init \n " ) ) ;
2006-12-12 17:52:13 +03:00
return smb_register_idmap ( SMB_IDMAP_INTERFACE_VERSION , " tdb " , & db_methods ) ;
}