2003-03-08 00:49:18 +00:00
/*
Unix SMB / CIFS implementation .
idmap TDB backend
Copyright ( C ) Tim Potter 2000
Copyright ( C ) Anthony Liguori 2003
Copyright ( C ) Simo Sorce 2003
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_IDMAP
/* High water mark keys */
# define HWM_GROUP "GROUP HWM"
# define HWM_USER "USER HWM"
/* idmap version determines auto-conversion */
# define IDMAP_VERSION 2
/* Globals */
static TDB_CONTEXT * idmap_tdb ;
2003-04-02 10:36:02 +00:00
static struct idmap_state {
2003-03-08 17:29:40 +00:00
/* User and group id pool */
uid_t uid_low , uid_high ; /* Range of uids to allocate */
gid_t gid_low , gid_high ; /* Range of gids to allocate */
} idmap_state ;
2003-03-08 00:49:18 +00:00
/* Allocate either a user or group id from the pool */
2003-04-02 10:36:02 +00:00
static NTSTATUS db_allocate_id ( unid_t * id , int id_type )
2003-03-08 00:49:18 +00:00
{
int hwm ;
if ( ! id ) return NT_STATUS_INVALID_PARAMETER ;
/* Get current high water mark */
2003-03-08 17:29:40 +00:00
switch ( id_type & ID_TYPEMASK ) {
2003-03-08 00:49:18 +00:00
case ID_USERID :
if ( ( hwm = tdb_fetch_int32 ( idmap_tdb , HWM_USER ) ) = = - 1 ) {
return NT_STATUS_INTERNAL_DB_ERROR ;
}
2003-03-08 17:29:40 +00:00
if ( hwm > idmap_state . uid_high ) {
2003-04-19 15:29:39 +00:00
DEBUG ( 0 , ( " idmap Fatal Error: UID range full!! (max: %u) \n " , idmap_state . uid_high ) ) ;
2003-03-08 00:49:18 +00:00
return NT_STATUS_UNSUCCESSFUL ;
}
2003-03-08 17:29:40 +00:00
( * id ) . uid = hwm + + ;
2003-03-08 00:49:18 +00:00
/* Store new high water mark */
tdb_store_int32 ( idmap_tdb , HWM_USER , hwm ) ;
break ;
case ID_GROUPID :
if ( ( hwm = tdb_fetch_int32 ( idmap_tdb , HWM_GROUP ) ) = = - 1 ) {
return NT_STATUS_INTERNAL_DB_ERROR ;
}
2003-03-08 17:29:40 +00:00
if ( hwm > idmap_state . gid_high ) {
2003-04-19 15:29:39 +00:00
DEBUG ( 0 , ( " idmap Fatal Error: GID range full!! (max: %u) \n " , idmap_state . gid_high ) ) ;
2003-03-08 00:49:18 +00:00
return NT_STATUS_UNSUCCESSFUL ;
}
2003-03-08 17:29:40 +00:00
( * id ) . gid = hwm + + ;
2003-03-08 00:49:18 +00:00
/* Store new high water mark */
tdb_store_int32 ( idmap_tdb , HWM_GROUP , hwm ) ;
break ;
default :
return NT_STATUS_INVALID_PARAMETER ;
}
return NT_STATUS_OK ;
}
/* Get a sid from an id */
2003-04-02 10:36:02 +00:00
static NTSTATUS db_get_sid_from_id ( DOM_SID * sid , unid_t id , int id_type )
2003-03-08 00:49:18 +00:00
{
TDB_DATA key , data ;
fstring keystr ;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL ;
if ( ! sid ) return NT_STATUS_INVALID_PARAMETER ;
2003-03-08 17:29:40 +00:00
switch ( id_type & ID_TYPEMASK ) {
2003-03-08 00:49:18 +00:00
case ID_USERID :
2003-04-02 10:36:02 +00:00
slprintf ( keystr , sizeof ( keystr ) , " UID %d " , id . uid ) ;
break ;
2003-03-08 00:49:18 +00:00
case ID_GROUPID :
2003-04-02 10:36:02 +00:00
slprintf ( keystr , sizeof ( keystr ) , " GID %d " , id . gid ) ;
break ;
2003-03-08 00:49:18 +00:00
default :
2003-04-02 10:36:02 +00:00
return NT_STATUS_UNSUCCESSFUL ;
2003-03-08 00:49:18 +00:00
}
key . dptr = keystr ;
key . dsize = strlen ( keystr ) + 1 ;
data = tdb_fetch ( idmap_tdb , key ) ;
if ( data . dptr ) {
if ( string_to_sid ( sid , data . dptr ) ) {
ret = NT_STATUS_OK ;
}
SAFE_FREE ( data . dptr ) ;
}
return ret ;
}
/* Get an id from a sid */
2003-04-04 00:28:38 +00:00
static NTSTATUS db_get_id_from_sid ( unid_t * id , int * id_type , const DOM_SID * sid )
2003-03-08 00:49:18 +00:00
{
TDB_DATA data , key ;
fstring keystr ;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL ;
if ( ! sid | | ! id | | ! id_type ) return NT_STATUS_INVALID_PARAMETER ;
/* Check if sid is present in database */
sid_to_string ( keystr , sid ) ;
key . dptr = keystr ;
key . dsize = strlen ( keystr ) + 1 ;
data = tdb_fetch ( idmap_tdb , key ) ;
if ( data . dptr ) {
2003-03-08 17:29:40 +00:00
int type = * id_type & ID_TYPEMASK ;
2003-03-08 00:49:18 +00:00
fstring scanstr ;
2003-03-08 17:29:40 +00:00
if ( type = = ID_EMPTY | | type = = ID_USERID ) {
2003-03-08 00:49:18 +00:00
/* Parse and return existing uid */
fstrcpy ( scanstr , " UID %d " ) ;
2003-04-02 10:36:02 +00:00
if ( sscanf ( data . dptr , scanstr , & ( ( * id ) . uid ) ) = = 1 ) {
2003-03-08 00:49:18 +00:00
/* uid ok? */
2003-03-08 17:29:40 +00:00
if ( type = = ID_EMPTY ) {
2003-03-08 00:49:18 +00:00
* id_type = ID_USERID ;
}
ret = NT_STATUS_OK ;
goto idok ;
}
}
2003-03-08 17:29:40 +00:00
if ( type = = ID_EMPTY | | type = = ID_GROUPID ) {
2003-03-08 00:49:18 +00:00
/* Parse and return existing gid */
fstrcpy ( scanstr , " GID %d " ) ;
2003-04-02 10:36:02 +00:00
if ( sscanf ( data . dptr , scanstr , & ( ( * id ) . gid ) ) = = 1 ) {
2003-03-08 00:49:18 +00:00
/* gid ok? */
2003-03-08 17:29:40 +00:00
if ( type = = ID_EMPTY ) {
2003-03-08 00:49:18 +00:00
* id_type = ID_GROUPID ;
}
ret = NT_STATUS_OK ;
}
}
idok :
SAFE_FREE ( data . dptr ) ;
2003-03-08 17:29:40 +00:00
} else if ( ! ( * id_type & ID_NOMAP ) & &
( ( ( * id_type & ID_TYPEMASK ) = = ID_USERID )
| | ( * id_type & ID_TYPEMASK ) = = ID_GROUPID ) ) {
2003-03-08 00:49:18 +00:00
/* Allocate a new id for this sid */
2003-04-02 10:36:02 +00:00
ret = db_allocate_id ( id , * id_type ) ;
2003-03-08 00:49:18 +00:00
if ( NT_STATUS_IS_OK ( ret ) ) {
fstring keystr2 ;
/* Store new id */
2003-03-08 17:29:40 +00:00
if ( * id_type & ID_USERID ) {
slprintf ( keystr2 , sizeof ( keystr2 ) , " UID %d " , ( * id ) . uid ) ;
} else {
slprintf ( keystr2 , sizeof ( keystr2 ) , " GID %d " , ( * id ) . gid ) ;
}
2003-03-08 00:49:18 +00:00
data . dptr = keystr2 ;
data . dsize = strlen ( keystr2 ) + 1 ;
2003-04-02 10:36:02 +00:00
if ( tdb_store ( idmap_tdb , key , data , TDB_REPLACE ) = = - 1 ) {
2003-03-08 17:29:40 +00:00
/* TODO: print tdb error !! */
2003-03-08 00:49:18 +00:00
return NT_STATUS_UNSUCCESSFUL ;
2003-03-08 17:29:40 +00:00
}
2003-04-02 10:36:02 +00:00
if ( tdb_store ( idmap_tdb , data , key , TDB_REPLACE ) = = - 1 ) {
2003-03-08 17:29:40 +00:00
/* TODO: print tdb error !! */
2003-03-08 00:49:18 +00:00
return NT_STATUS_UNSUCCESSFUL ;
2003-03-08 17:29:40 +00:00
}
2003-03-08 00:49:18 +00:00
ret = NT_STATUS_OK ;
}
}
2003-04-02 10:36:02 +00:00
2003-03-08 00:49:18 +00:00
return ret ;
}
2003-04-26 15:48:48 +00:00
static NTSTATUS db_set_mapping ( const DOM_SID * sid , unid_t id , int id_type )
2003-03-08 17:29:40 +00:00
{
TDB_DATA ksid , kid ;
fstring ksidstr ;
fstring kidstr ;
if ( ! sid ) return NT_STATUS_INVALID_PARAMETER ;
sid_to_string ( ksidstr , sid ) ;
ksid . dptr = ksidstr ;
ksid . dsize = strlen ( ksidstr ) + 1 ;
if ( id_type & ID_USERID ) {
slprintf ( kidstr , sizeof ( kidstr ) , " UID %d " , id . uid ) ;
} else if ( id_type & ID_GROUPID ) {
slprintf ( kidstr , sizeof ( kidstr ) , " GID %d " , id . gid ) ;
} else {
return NT_STATUS_INVALID_PARAMETER ;
}
kid . dptr = kidstr ;
kid . dsize = strlen ( kidstr ) + 1 ;
if ( tdb_store ( idmap_tdb , ksid , kid , TDB_INSERT ) = = - 1 ) {
2003-04-17 14:25:52 +00:00
DEBUG ( 0 , ( " idb_set_mapping: tdb_store 1 error: %s \n " , tdb_errorstr ( idmap_tdb ) ) ) ;
2003-03-08 17:29:40 +00:00
return NT_STATUS_UNSUCCESSFUL ;
}
if ( tdb_store ( idmap_tdb , kid , ksid , TDB_INSERT ) = = - 1 ) {
2003-04-17 14:25:52 +00:00
DEBUG ( 0 , ( " idb_set_mapping: tdb_store 2 error: %s \n " , tdb_errorstr ( idmap_tdb ) ) ) ;
2003-03-08 17:29:40 +00:00
return NT_STATUS_UNSUCCESSFUL ;
}
return NT_STATUS_OK ;
}
2003-03-08 00:49:18 +00:00
/*****************************************************************************
Initialise idmap database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-04-06 09:35:16 +00:00
static NTSTATUS db_idmap_init ( void )
2003-03-08 00:49:18 +00:00
{
2003-04-06 09:35:16 +00:00
SMB_STRUCT_STAT stbuf ;
2003-04-26 15:48:48 +00:00
char * tdbfile ;
int32 version ;
2003-04-06 09:35:16 +00:00
2003-04-26 15:48:48 +00:00
/* use the old database if present */
2003-04-06 09:35:16 +00:00
if ( ! file_exist ( lock_path ( " idmap.tdb " ) , & stbuf ) ) {
if ( file_exist ( lock_path ( " winbindd_idmap.tdb " ) , & stbuf ) ) {
2003-04-26 15:48:48 +00:00
DEBUG ( 0 , ( " idmap_init: using winbindd_idmap.tdb file! \n " ) ) ;
tdbfile = strdup ( lock_path ( " winbindd_idmap.tdb " ) ) ;
if ( ! tdbfile ) {
DEBUG ( 0 , ( " idmap_init: out of memory! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
}
} else {
tdbfile = strdup ( lock_path ( " idmap.tdb " ) ) ;
if ( ! tdbfile ) {
DEBUG ( 0 , ( " idmap_init: out of memory! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
2003-04-06 09:35:16 +00:00
}
}
2003-03-08 00:49:18 +00:00
/* Open tdb cache */
2003-04-26 15:48:48 +00:00
if ( ! ( idmap_tdb = tdb_open_log ( tdbfile , 0 ,
2003-03-08 00:49:18 +00:00
TDB_DEFAULT , O_RDWR | O_CREAT ,
0600 ) ) ) {
DEBUG ( 0 , ( " idmap_init: Unable to open idmap database \n " ) ) ;
2003-04-26 15:48:48 +00:00
SAFE_FREE ( tdbfile ) ;
2003-03-08 00:49:18 +00:00
return NT_STATUS_UNSUCCESSFUL ;
}
2003-04-26 15:48:48 +00:00
SAFE_FREE ( tdbfile ) ;
/* check against earlier versions */
version = tdb_fetch_int32 ( idmap_tdb , " IDMAP_VERSION " ) ;
if ( version ! = IDMAP_VERSION ) {
DEBUG ( 0 , ( " idmap_init: Unable to open idmap database, it's in an old format! \n " ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
2003-03-08 00:49:18 +00:00
/* Create high water marks for group and user id */
if ( tdb_fetch_int32 ( idmap_tdb , HWM_USER ) = = - 1 ) {
2003-03-08 17:29:40 +00:00
if ( tdb_store_int32 ( idmap_tdb , HWM_USER , idmap_state . uid_low ) = = - 1 ) {
2003-03-08 00:49:18 +00:00
DEBUG ( 0 , ( " idmap_init: Unable to initialise user hwm in idmap database \n " ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
}
if ( tdb_fetch_int32 ( idmap_tdb , HWM_GROUP ) = = - 1 ) {
2003-03-08 17:29:40 +00:00
if ( tdb_store_int32 ( idmap_tdb , HWM_GROUP , idmap_state . gid_low ) = = - 1 ) {
2003-03-08 00:49:18 +00:00
DEBUG ( 0 , ( " idmap_init: Unable to initialise group hwm in idmap database \n " ) ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
}
2003-04-19 15:29:39 +00:00
if ( ! lp_idmap_uid ( & idmap_state . uid_low , & idmap_state . uid_high ) ) {
DEBUG ( 0 , ( " idmap uid range missing or invalid \n " ) ) ;
DEBUGADD ( 0 , ( " idmap will be unable to map foreign SIDs \n " ) ) ;
}
if ( ! lp_idmap_gid ( & idmap_state . gid_low , & idmap_state . gid_high ) ) {
DEBUG ( 0 , ( " idmap gid range missing or invalid \n " ) ) ;
DEBUGADD ( 0 , ( " idmap will be unable to map foreign SIDs \n " ) ) ;
}
2003-03-08 00:49:18 +00:00
return NT_STATUS_OK ;
}
/* Close the tdb */
2003-04-02 10:36:02 +00:00
static NTSTATUS db_idmap_close ( void )
2003-03-08 00:49:18 +00:00
{
2003-03-08 17:29:40 +00:00
if ( idmap_tdb ) {
if ( tdb_close ( idmap_tdb ) = = 0 ) {
2003-03-08 00:49:18 +00:00
return NT_STATUS_OK ;
2003-03-08 17:29:40 +00:00
} else {
return NT_STATUS_UNSUCCESSFUL ;
}
}
2003-03-08 00:49:18 +00:00
return NT_STATUS_OK ;
}
/* Dump status information to log file. Display different stuff based on
the debug level :
Debug Level Information Displayed
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
0 Percentage of [ ug ] id range allocated
0 High water marks ( next allocated ids )
*/
# define DUMP_INFO 0
2003-04-02 10:36:02 +00:00
static void db_idmap_status ( void )
2003-03-08 00:49:18 +00:00
{
int user_hwm , group_hwm ;
DEBUG ( 0 , ( " winbindd idmap status: \n " ) ) ;
/* Get current high water marks */
if ( ( user_hwm = tdb_fetch_int32 ( idmap_tdb , HWM_USER ) ) = = - 1 ) {
DEBUG ( DUMP_INFO ,
( " \t Could not get userid high water mark! \n " ) ) ;
}
if ( ( group_hwm = tdb_fetch_int32 ( idmap_tdb , HWM_GROUP ) ) = = - 1 ) {
DEBUG ( DUMP_INFO ,
( " \t Could not get groupid high water mark! \n " ) ) ;
}
/* Display next ids to allocate */
if ( user_hwm ! = - 1 ) {
DEBUG ( DUMP_INFO ,
( " \t Next userid to allocate is %d \n " , user_hwm ) ) ;
}
if ( group_hwm ! = - 1 ) {
DEBUG ( DUMP_INFO ,
( " \t Next groupid to allocate is %d \n " , group_hwm ) ) ;
}
/* Display percentage of id range already allocated. */
if ( user_hwm ! = - 1 ) {
2003-03-08 17:29:40 +00:00
int num_users = user_hwm - idmap_state . uid_low ;
2003-03-08 00:49:18 +00:00
int total_users =
2003-03-08 17:29:40 +00:00
idmap_state . uid_high - idmap_state . uid_low ;
2003-03-08 00:49:18 +00:00
DEBUG ( DUMP_INFO ,
( " \t User id range is %d%% full (%d of %d) \n " ,
num_users * 100 / total_users , num_users ,
total_users ) ) ;
}
if ( group_hwm ! = - 1 ) {
2003-03-08 17:29:40 +00:00
int num_groups = group_hwm - idmap_state . gid_low ;
2003-03-08 00:49:18 +00:00
int total_groups =
2003-03-08 17:29:40 +00:00
idmap_state . gid_high - idmap_state . gid_low ;
2003-03-08 00:49:18 +00:00
DEBUG ( DUMP_INFO ,
( " \t Group id range is %d%% full (%d of %d) \n " ,
num_groups * 100 / total_groups , num_groups ,
total_groups ) ) ;
}
/* Display complete mapping of users and groups to rids */
}
2003-04-02 10:36:02 +00:00
struct idmap_methods db_methods = {
2003-03-08 00:49:18 +00:00
2003-04-02 10:36:02 +00:00
db_idmap_init ,
db_get_sid_from_id ,
db_get_id_from_sid ,
db_set_mapping ,
db_idmap_close ,
db_idmap_status
2003-03-08 00:49:18 +00:00
} ;
NTSTATUS idmap_reg_tdb ( struct idmap_methods * * meth )
{
2003-04-02 10:36:02 +00:00
* meth = & db_methods ;
2003-03-08 00:49:18 +00:00
2003-03-08 17:29:40 +00:00
return NT_STATUS_OK ;
2003-03-08 00:49:18 +00:00
}