2000-05-09 11:43:00 +00:00
/*
2002-01-30 06:08:46 +00:00
Unix SMB / CIFS implementation .
2000-05-09 11:43:00 +00:00
Winbind daemon - user related function
Copyright ( C ) Tim Potter 2000
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 "winbindd.h"
2002-07-15 10:35:28 +00:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2000-05-09 11:43:00 +00:00
/* High water mark keys */
# define HWM_GROUP "GROUP HWM"
# define HWM_USER "USER HWM"
2002-02-27 23:51:25 +00:00
/* idmap version determines auto-conversion */
# define IDMAP_VERSION 2
2000-05-09 11:43:00 +00:00
/* Globals */
static TDB_CONTEXT * idmap_tdb ;
/* Allocate either a user or group id from the pool */
2001-09-05 07:55:54 +00:00
static BOOL allocate_id ( uid_t * id , BOOL isgroup )
2000-05-09 11:43:00 +00:00
{
int hwm ;
/* Get current high water mark */
2002-03-21 23:41:28 +00:00
if ( ( hwm = tdb_fetch_int32 ( idmap_tdb ,
2000-05-12 06:27:35 +00:00
isgroup ? HWM_GROUP : HWM_USER ) ) = = - 1 ) {
2000-05-09 11:43:00 +00:00
return False ;
}
/* Return next available uid in list */
if ( ( isgroup & & ( hwm > server_state . gid_high ) ) | |
( ! isgroup & & ( hwm > server_state . uid_high ) ) ) {
DEBUG ( 0 , ( " winbind %sid range full! \n " , isgroup ? " g " : " u " ) ) ;
return False ;
}
if ( id ) {
* id = hwm ;
}
hwm + + ;
/* Store new high water mark */
2002-03-21 23:41:28 +00:00
tdb_store_int32 ( idmap_tdb , isgroup ? HWM_GROUP : HWM_USER , hwm ) ;
2000-05-09 11:43:00 +00:00
return True ;
}
/* Get an id from a rid */
2002-02-27 23:51:25 +00:00
static BOOL get_id_from_sid ( DOM_SID * sid , uid_t * id , BOOL isgroup )
2000-05-09 11:43:00 +00:00
{
TDB_DATA data , key ;
fstring keystr ;
2001-05-07 04:32:40 +00:00
BOOL result = False ;
2000-05-09 11:43:00 +00:00
2002-02-27 23:51:25 +00:00
/* Check if sid is present in database */
sid_to_string ( keystr , sid ) ;
2000-05-09 11:43:00 +00:00
key . dptr = keystr ;
key . dsize = strlen ( keystr ) + 1 ;
data = tdb_fetch ( idmap_tdb , key ) ;
if ( data . dptr ) {
fstring scanstr ;
int the_id ;
/* Parse and return existing uid */
fstrcpy ( scanstr , isgroup ? " GID " : " UID " ) ;
fstrcat ( scanstr , " %d " ) ;
if ( sscanf ( data . dptr , scanstr , & the_id ) = = 1 ) {
/* Store uid */
if ( id ) {
2002-02-27 23:51:25 +00:00
* id = the_id ;
2000-05-09 11:43:00 +00:00
}
result = True ;
}
2001-09-17 04:52:45 +00:00
SAFE_FREE ( data . dptr ) ;
2000-05-09 11:43:00 +00:00
} else {
2002-02-27 23:51:25 +00:00
/* Allocate a new id for this sid */
2000-05-09 11:43:00 +00:00
if ( id & & allocate_id ( id , isgroup ) ) {
fstring keystr2 ;
/* Store new id */
2002-02-27 23:51:25 +00:00
slprintf ( keystr2 , sizeof ( keystr2 ) , " %s %d " , isgroup ? " GID " : " UID " , * id ) ;
2000-05-09 11:43:00 +00:00
data . dptr = keystr2 ;
data . dsize = strlen ( keystr2 ) + 1 ;
tdb_store ( idmap_tdb , key , data , TDB_REPLACE ) ;
tdb_store ( idmap_tdb , data , key , TDB_REPLACE ) ;
result = True ;
}
}
return result ;
}
2002-02-27 23:51:25 +00:00
/* Get a uid from a user sid */
BOOL winbindd_idmap_get_uid_from_sid ( DOM_SID * sid , uid_t * uid )
{
return get_id_from_sid ( sid , uid , False ) ;
}
2000-05-09 11:43:00 +00:00
2002-02-27 23:51:25 +00:00
/* Get a gid from a group sid */
BOOL winbindd_idmap_get_gid_from_sid ( DOM_SID * sid , gid_t * gid )
2000-05-09 11:43:00 +00:00
{
2002-02-27 23:51:25 +00:00
return get_id_from_sid ( sid , gid , True ) ;
2000-05-09 11:43:00 +00:00
}
2002-02-27 23:51:25 +00:00
/* Get a uid from a user rid */
BOOL winbindd_idmap_get_uid_from_rid ( const char * dom_name , uint32 rid , uid_t * uid )
{
struct winbindd_domain * domain ;
DOM_SID sid ;
if ( ! ( domain = find_domain_from_name ( dom_name ) ) ) {
return False ;
}
sid_copy ( & sid , & domain - > sid ) ;
sid_append_rid ( & sid , rid ) ;
return get_id_from_sid ( & sid , uid , False ) ;
}
2000-05-09 11:43:00 +00:00
2002-02-27 23:51:25 +00:00
/* Get a gid from a group rid */
BOOL winbindd_idmap_get_gid_from_rid ( const char * dom_name , uint32 rid , gid_t * gid )
2000-05-09 11:43:00 +00:00
{
2002-02-27 23:51:25 +00:00
struct winbindd_domain * domain ;
DOM_SID sid ;
if ( ! ( domain = find_domain_from_name ( dom_name ) ) ) {
return False ;
}
sid_copy ( & sid , & domain - > sid ) ;
sid_append_rid ( & sid , rid ) ;
return get_id_from_sid ( & sid , gid , True ) ;
2000-05-09 11:43:00 +00:00
}
2002-02-27 23:51:25 +00:00
BOOL get_sid_from_id ( int id , DOM_SID * sid , BOOL isgroup )
2000-05-09 11:43:00 +00:00
{
TDB_DATA key , data ;
fstring keystr ;
BOOL result = False ;
2001-05-07 04:32:40 +00:00
slprintf ( keystr , sizeof ( keystr ) , " %s %d " , isgroup ? " GID " : " UID " , id ) ;
2000-05-09 11:43:00 +00:00
key . dptr = keystr ;
key . dsize = strlen ( keystr ) + 1 ;
data = tdb_fetch ( idmap_tdb , key ) ;
if ( data . dptr ) {
2002-02-27 23:51:25 +00:00
result = string_to_sid ( sid , data . dptr ) ;
SAFE_FREE ( data . dptr ) ;
2000-05-09 11:43:00 +00:00
}
return result ;
}
2002-02-27 23:51:25 +00:00
/* Get a sid from a uid */
BOOL winbindd_idmap_get_sid_from_uid ( uid_t uid , DOM_SID * sid )
{
return get_sid_from_id ( ( int ) uid , sid , False ) ;
}
2000-05-09 11:43:00 +00:00
2002-02-27 23:51:25 +00:00
/* Get a sid from a gid */
BOOL winbindd_idmap_get_sid_from_gid ( gid_t gid , DOM_SID * sid )
{
return get_sid_from_id ( ( int ) gid , sid , True ) ;
}
/* Get a user rid from a uid */
2000-05-09 11:43:00 +00:00
BOOL winbindd_idmap_get_rid_from_uid ( uid_t uid , uint32 * user_rid ,
struct winbindd_domain * * domain )
{
2002-02-27 23:51:25 +00:00
DOM_SID sid ;
if ( ! get_sid_from_id ( ( int ) uid , & sid , False ) ) {
return False ;
}
* domain = find_domain_from_sid ( & sid ) ;
if ( ! * domain ) return False ;
sid_split_rid ( & sid , user_rid ) ;
return True ;
2000-05-09 11:43:00 +00:00
}
/* Get a group rid from a gid */
BOOL winbindd_idmap_get_rid_from_gid ( gid_t gid , uint32 * group_rid ,
struct winbindd_domain * * domain )
{
2002-02-27 23:51:25 +00:00
DOM_SID sid ;
if ( ! get_sid_from_id ( ( int ) gid , & sid , True ) ) {
return False ;
}
* domain = find_domain_from_sid ( & sid ) ;
if ( ! * domain ) return False ;
sid_split_rid ( & sid , group_rid ) ;
return True ;
}
/* convert one record to the new format */
static int convert_fn ( TDB_CONTEXT * tdb , TDB_DATA key , TDB_DATA data , void * ignored )
{
struct winbindd_domain * domain ;
2002-04-04 03:03:39 +00:00
char * p ;
2002-02-27 23:51:25 +00:00
DOM_SID sid ;
uint32 rid ;
fstring keystr ;
2002-04-04 03:03:39 +00:00
fstring dom_name ;
2002-02-27 23:51:25 +00:00
TDB_DATA key2 ;
p = strchr ( key . dptr , ' / ' ) ;
2002-04-04 03:03:39 +00:00
if ( ! p )
return 0 ;
2002-02-27 23:51:25 +00:00
2002-04-04 03:03:39 +00:00
* p = 0 ;
fstrcpy ( dom_name , key . dptr ) ;
* p + + = ' / ' ;
2002-02-27 23:51:25 +00:00
domain = find_domain_from_name ( dom_name ) ;
if ( ! domain ) {
2002-04-04 03:03:39 +00:00
/* We must delete the old record. */
2002-03-21 23:39:17 +00:00
DEBUG ( 0 , ( " winbindd: convert_fn : Unable to find domain %s \n " , dom_name ) ) ;
2002-04-04 03:03:39 +00:00
DEBUG ( 0 , ( " winbindd: convert_fn : deleting record %s \n " , key . dptr ) ) ;
tdb_delete ( idmap_tdb , key ) ;
return 0 ;
2002-02-27 23:51:25 +00:00
}
rid = atoi ( p ) ;
sid_copy ( & sid , & domain - > sid ) ;
sid_append_rid ( & sid , rid ) ;
sid_to_string ( keystr , & sid ) ;
key2 . dptr = keystr ;
key2 . dsize = strlen ( keystr ) + 1 ;
if ( tdb_store ( idmap_tdb , key2 , data , TDB_INSERT ) ! = 0 ) {
/* not good! */
2002-03-21 23:39:17 +00:00
DEBUG ( 0 , ( " winbindd: convert_fn : Unable to update record %s \n " , key2 . dptr ) ) ;
DEBUG ( 0 , ( " winbindd: convert_fn : conversion failed - idmap corrupt ? \n " ) ) ;
return - 1 ;
2002-02-27 23:51:25 +00:00
}
2002-03-21 23:19:17 +00:00
if ( tdb_store ( idmap_tdb , data , key2 , TDB_REPLACE ) ! = 0 ) {
/* not good! */
2002-03-21 23:39:17 +00:00
DEBUG ( 0 , ( " winbindd: convert_fn : Unable to update record %s \n " , data . dptr ) ) ;
DEBUG ( 0 , ( " winbindd: convert_fn : conversion failed - idmap corrupt ? \n " ) ) ;
return - 1 ;
2002-03-21 23:19:17 +00:00
}
2002-02-27 23:51:25 +00:00
tdb_delete ( idmap_tdb , key ) ;
return 0 ;
}
2002-04-04 03:03:39 +00:00
#if 0
/*****************************************************************************
Make a backup copy of the old idmap just to be safe . . . . JRA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL backup_old_idmap ( const char * idmap_name )
{
pstring new_name ;
int outfd = - 1 ;
SMB_OFF_T size ;
struct stat st ;
pstrcpy ( new_name , idmap_name ) ;
pstrcat ( new_name , " .bak " ) ;
DEBUG ( 10 , ( " backup_old_idmap: backing up %s to %s before upgrade. \n " ,
idmap_name , new_name ) ) ;
if ( tdb_lockall ( idmap_tdb ) = = - 1 ) {
DEBUG ( 10 , ( " backup_old_idmap: failed to lock %s. Error %s \n " ,
idmap_name , tdb_errorstr ( idmap_tdb ) ) ) ;
return False ;
}
if ( ( outfd = open ( new_name , O_CREAT | O_EXCL | O_RDWR , 0600 ) ) = = - 1 ) {
DEBUG ( 10 , ( " backup_old_idmap: failed to open %s. Error %s \n " ,
new_name , strerror ( errno ) ) ) ;
goto fail ;
}
if ( fstat ( idmap_tdb - > fd , & st ) = = - 1 ) {
DEBUG ( 10 , ( " backup_old_idmap: failed to fstat %s. Error %s \n " ,
idmap_name , strerror ( errno ) ) ) ;
goto fail ;
}
size = ( SMB_OFF_T ) st . st_size ;
if ( transfer_file ( idmap_tdb - > fd , outfd , size ) ! = size ) {
DEBUG ( 10 , ( " backup_old_idmap: failed to copy %s. Error %s \n " ,
idmap_name , strerror ( errno ) ) ) ;
goto fail ;
}
if ( close ( outfd ) = = - 1 ) {
DEBUG ( 10 , ( " backup_old_idmap: failed to close %s. Error %s \n " ,
idmap_name , strerror ( errno ) ) ) ;
outfd = - 1 ;
goto fail ;
}
tdb_unlockall ( idmap_tdb ) ;
return True ;
fail :
if ( outfd ! = - 1 )
close ( outfd ) ;
tdb_unlockall ( idmap_tdb ) ;
return False ;
}
# endif
/*****************************************************************************
Convert the idmap database from an older version .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL idmap_convert ( const char * idmap_name )
2002-02-27 23:51:25 +00:00
{
2002-03-21 23:39:17 +00:00
int32 vers = tdb_fetch_int32 ( idmap_tdb , " IDMAP_VERSION " ) ;
2002-07-15 10:35:28 +00:00
BOOL bigendianheader = ( idmap_tdb - > flags & TDB_BIGENDIAN ) ? True : False ;
2002-03-21 23:39:17 +00:00
if ( vers = = IDMAP_VERSION )
2002-02-27 23:51:25 +00:00
return True ;
2002-03-21 23:39:17 +00:00
2002-04-04 03:03:39 +00:00
#if 0
/* Make a backup copy before doing anything else.... */
if ( ! backup_old_idmap ( idmap_name ) )
return False ;
# endif
2002-07-15 10:35:28 +00: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 .
*/
2002-03-21 23:39:17 +00:00
int32 wm ;
wm = tdb_fetch_int32 ( idmap_tdb , HWM_USER ) ;
2002-07-15 10:35:28 +00:00
if ( wm ! = - 1 ) {
2002-03-21 23:39:17 +00:00
wm = IREV ( wm ) ;
2002-07-15 10:35:28 +00:00
} else
2002-03-21 23:39:17 +00:00
wm = server_state . uid_low ;
2002-07-15 10:35:28 +00:00
if ( tdb_store_int32 ( idmap_tdb , HWM_USER , wm ) = = - 1 ) {
2002-03-21 23:39:17 +00:00
DEBUG ( 0 , ( " idmap_convert: Unable to byteswap user hwm in idmap database \n " ) ) ;
return False ;
}
wm = tdb_fetch_int32 ( idmap_tdb , HWM_GROUP ) ;
2002-07-15 10:35:28 +00:00
if ( wm ! = - 1 ) {
2002-03-21 23:39:17 +00:00
wm = IREV ( wm ) ;
2002-07-15 10:35:28 +00:00
} else
2002-03-21 23:39:17 +00:00
wm = server_state . gid_low ;
2002-07-15 10:35:28 +00:00
if ( tdb_store_int32 ( idmap_tdb , HWM_GROUP , wm ) = = - 1 ) {
2002-03-21 23:39:17 +00:00
DEBUG ( 0 , ( " idmap_convert: Unable to byteswap group hwm in idmap database \n " ) ) ;
return False ;
}
2002-02-27 23:51:25 +00:00
}
/* the old format stored as DOMAIN/rid - now we store the SID direct */
tdb_traverse ( idmap_tdb , convert_fn , NULL ) ;
2002-07-15 10:35:28 +00:00
if ( tdb_store_int32 ( idmap_tdb , " IDMAP_VERSION " , IDMAP_VERSION ) = = - 1 ) {
2002-03-21 23:39:17 +00:00
DEBUG ( 0 , ( " idmap_convert: Unable to byteswap group hwm in idmap database \n " ) ) ;
2002-02-27 23:51:25 +00:00
return False ;
}
return True ;
2000-05-09 11:43:00 +00:00
}
2002-04-04 03:03:39 +00:00
/*****************************************************************************
Initialise idmap database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-05-09 11:43:00 +00:00
BOOL winbindd_idmap_init ( void )
{
2002-04-04 03:03:39 +00:00
/* Open tdb cache */
2000-05-09 11:43:00 +00:00
2002-04-04 03:03:39 +00:00
if ( ! ( idmap_tdb = tdb_open_log ( lock_path ( " winbindd_idmap.tdb " ) , 0 ,
TDB_DEFAULT , O_RDWR | O_CREAT , 0600 ) ) ) {
DEBUG ( 0 , ( " winbindd_idmap_init: Unable to open idmap database \n " ) ) ;
return False ;
}
2000-05-09 11:43:00 +00:00
2002-04-04 03:03:39 +00:00
/* possibly convert from an earlier version */
if ( ! idmap_convert ( lock_path ( " winbindd_idmap.tdb " ) ) ) {
DEBUG ( 0 , ( " winbindd_idmap_init: Unable to open idmap database \n " ) ) ;
return False ;
}
2002-02-27 23:51:25 +00:00
2002-04-04 03:03:39 +00:00
/* Create high water marks for group and user id */
2000-05-09 11:43:00 +00:00
2002-04-04 03:03:39 +00:00
if ( tdb_fetch_int32 ( idmap_tdb , HWM_USER ) = = - 1 ) {
if ( tdb_store_int32 ( idmap_tdb , HWM_USER , server_state . uid_low ) = = - 1 ) {
DEBUG ( 0 , ( " winbindd_idmap_init: Unable to initialise user hwm in idmap database \n " ) ) ;
return False ;
}
}
2000-05-09 11:43:00 +00:00
2002-04-04 03:03:39 +00:00
if ( tdb_fetch_int32 ( idmap_tdb , HWM_GROUP ) = = - 1 ) {
if ( tdb_store_int32 ( idmap_tdb , HWM_GROUP , server_state . gid_low ) = = - 1 ) {
DEBUG ( 0 , ( " winbindd_idmap_init: Unable to initialise group hwm in idmap database \n " ) ) ;
return False ;
}
}
2000-05-09 11:43:00 +00:00
2002-04-04 03:03:39 +00:00
return True ;
2000-05-09 11:43:00 +00:00
}
2001-05-07 04:32:40 +00:00
2002-01-19 20:21:29 +00:00
BOOL winbindd_idmap_close ( void )
{
if ( idmap_tdb )
return ( tdb_close ( idmap_tdb ) = = 0 ) ;
return True ;
}
2001-05-07 04:32:40 +00:00
/* 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
2001-11-14 06:18:13 +00:00
void winbindd_idmap_status ( void )
2001-05-07 04:32:40 +00:00
{
2002-04-04 03:03:39 +00:00
int user_hwm , group_hwm ;
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
DEBUG ( 0 , ( " winbindd idmap status: \n " ) ) ;
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
/* Get current high water marks */
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
if ( ( user_hwm = tdb_fetch_int32 ( idmap_tdb , HWM_USER ) ) = = - 1 ) {
DEBUG ( DUMP_INFO , ( " \t Could not get userid high water mark! \n " ) ) ;
}
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
if ( ( group_hwm = tdb_fetch_int32 ( idmap_tdb , HWM_GROUP ) ) = = - 1 ) {
DEBUG ( DUMP_INFO , ( " \t Could not get groupid high water mark! \n " ) ) ;
}
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
/* Display next ids to allocate */
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
if ( user_hwm ! = - 1 ) {
DEBUG ( DUMP_INFO , ( " \t Next userid to allocate is %d \n " , user_hwm ) ) ;
}
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
if ( group_hwm ! = - 1 ) {
DEBUG ( DUMP_INFO , ( " \t Next groupid to allocate is %d \n " , group_hwm ) ) ;
}
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
/* Display percentage of id range already allocated. */
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
if ( user_hwm ! = - 1 ) {
int num_users = user_hwm - server_state . uid_low ;
int total_users = server_state . uid_high - server_state . uid_low ;
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +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 ) ) ;
}
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
if ( group_hwm ! = - 1 ) {
int num_groups = group_hwm - server_state . gid_low ;
int total_groups = server_state . gid_high - server_state . gid_low ;
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +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 ) ) ;
}
2001-05-07 04:32:40 +00:00
2002-04-04 03:03:39 +00:00
/* Display complete mapping of users and groups to rids */
2001-05-07 04:32:40 +00:00
}