2008-07-17 15:32:28 +04:00
/*
2006-12-12 17:52:13 +03:00
Unix SMB / CIFS implementation .
ID Mapping Cache
2008-07-17 15:32:28 +04:00
Copyright ( C ) Volker Lendecke 2008
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 .
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
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"
2010-08-18 20:13:42 +04:00
# include "idmap_cache.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2012-03-23 14:01:01 +04:00
# include "../librpc/gen_ndr/idmap.h"
2006-12-12 17:52:13 +03:00
2008-07-17 15:32:28 +04:00
/**
2012-03-23 14:01:01 +04:00
* Find a sid2xid mapping
2008-07-17 15:32:28 +04:00
* @ param [ in ] sid the sid to map
2012-03-23 14:01:01 +04:00
* @ param [ out ] id where to put the result
2008-07-17 15:32:28 +04:00
* @ param [ out ] expired is the cache entry expired ?
* @ retval Was anything in the cache at all ?
*
2012-03-23 14:01:01 +04:00
* If id - > id = = - 1 this was a negative mapping .
2008-07-17 15:32:28 +04:00
*/
2012-03-23 14:01:01 +04:00
bool idmap_cache_find_sid2unixid ( const struct dom_sid * sid , struct unixid * id ,
bool * expired )
2008-07-08 00:09:39 +04:00
{
fstring sidstr ;
char * key ;
2012-05-17 01:10:04 +04:00
char * value = NULL ;
2008-07-08 00:09:39 +04:00
char * endptr ;
time_t timeout ;
bool ret ;
2012-03-23 14:01:01 +04:00
struct unixid tmp_id ;
2008-07-08 00:09:39 +04:00
2012-03-23 14:01:01 +04:00
key = talloc_asprintf ( talloc_tos ( ) , " IDMAP/SID2XID/%s " ,
2008-07-08 00:09:39 +04:00
sid_to_fstring ( sidstr , sid ) ) ;
if ( key = = NULL ) {
return false ;
}
2013-09-04 10:57:59 +04:00
ret = gencache_get ( key , talloc_tos ( ) , & value , & timeout ) ;
2008-07-08 00:09:39 +04:00
if ( ! ret ) {
2012-05-17 01:10:04 +04:00
goto done ;
2008-07-08 00:09:39 +04:00
}
2012-05-16 19:49:47 +04:00
DEBUG ( 10 , ( " Parsing value for key [%s]: value=[%s] \n " , key , value ) ) ;
2012-05-18 13:37:18 +04:00
if ( value [ 0 ] = = ' \0 ' ) {
DEBUG ( 0 , ( " Failed to parse value for key [%s]: "
" value is empty \n " , key ) ) ;
ret = false ;
goto done ;
}
2012-03-23 14:01:01 +04:00
tmp_id . id = strtol ( value , & endptr , 10 ) ;
2012-05-18 13:37:18 +04:00
if ( ( value = = endptr ) & & ( tmp_id . id = = 0 ) ) {
DEBUG ( 0 , ( " Failed to parse value for key [%s]: value[%s] does "
" not start with a number \n " , key , value ) ) ;
ret = false ;
goto done ;
}
2012-05-16 19:49:47 +04:00
DEBUG ( 10 , ( " Parsing value for key [%s]: id=[%llu], endptr=[%s] \n " ,
key , ( unsigned long long ) tmp_id . id , endptr ) ) ;
2012-03-23 14:01:01 +04:00
ret = ( * endptr = = ' : ' ) ;
2008-07-08 00:09:39 +04:00
if ( ret ) {
2012-03-23 14:01:01 +04:00
switch ( endptr [ 1 ] ) {
case ' U ' :
tmp_id . type = ID_TYPE_UID ;
break ;
case ' G ' :
tmp_id . type = ID_TYPE_GID ;
break ;
case ' B ' :
tmp_id . type = ID_TYPE_BOTH ;
break ;
2012-06-20 16:07:51 +04:00
case ' N ' :
tmp_id . type = ID_TYPE_NOT_SPECIFIED ;
break ;
2012-03-23 14:01:01 +04:00
case ' \0 ' :
2012-05-16 19:49:47 +04:00
DEBUG ( 0 , ( " FAILED to parse value for key [%s] "
" (id=[%llu], endptr=[%s]): "
" no type character after colon \n " ,
key , ( unsigned long long ) tmp_id . id , endptr ) ) ;
2012-05-17 01:10:04 +04:00
ret = false ;
goto done ;
2012-03-23 14:01:01 +04:00
default :
2012-05-16 19:49:47 +04:00
DEBUG ( 0 , ( " FAILED to parse value for key [%s] "
" (id=[%llu], endptr=[%s]): "
" illegal type character '%c' \n " ,
key , ( unsigned long long ) tmp_id . id , endptr ,
endptr [ 1 ] ) ) ;
2012-05-17 01:10:04 +04:00
ret = false ;
goto done ;
2012-03-23 14:01:01 +04:00
}
if ( endptr [ 2 ] ! = ' \0 ' ) {
2012-05-16 19:49:47 +04:00
DEBUG ( 0 , ( " FAILED to parse value for key [%s] "
" (id=[%llu], endptr=[%s]): "
" more than 1 type character after colon \n " ,
key , ( unsigned long long ) tmp_id . id , endptr ) ) ;
2012-05-17 01:10:04 +04:00
ret = false ;
goto done ;
2012-03-23 14:01:01 +04:00
}
* id = tmp_id ;
2008-07-08 00:09:39 +04:00
* expired = ( timeout < = time ( NULL ) ) ;
2012-03-23 14:01:01 +04:00
} else {
2012-05-16 19:49:47 +04:00
DEBUG ( 0 , ( " FAILED to parse value for key [%s] (value=[%s]): "
" colon missing after id=[%llu] \n " ,
key , value , ( unsigned long long ) tmp_id . id ) ) ;
2008-07-08 00:09:39 +04:00
}
2012-05-17 01:10:04 +04:00
done :
2012-03-23 14:01:01 +04:00
TALLOC_FREE ( key ) ;
2013-09-04 10:57:59 +04:00
TALLOC_FREE ( value ) ;
2008-07-08 00:09:39 +04:00
return ret ;
}
2008-07-17 15:32:28 +04:00
/**
2012-03-23 14:01:01 +04:00
* Find a sid2uid mapping
* @ param [ in ] sid the sid to map
* @ param [ out ] puid where to put the result
2008-07-17 15:32:28 +04:00
* @ param [ out ] expired is the cache entry expired ?
* @ retval Was anything in the cache at all ?
*
2012-03-23 14:01:01 +04:00
* If * puid = = - 1 this was a negative mapping .
2008-07-17 15:32:28 +04:00
*/
2012-03-23 14:01:01 +04:00
bool idmap_cache_find_sid2uid ( const struct dom_sid * sid , uid_t * puid ,
bool * expired )
2008-07-08 00:09:39 +04:00
{
2012-03-23 14:01:01 +04:00
bool ret ;
struct unixid id ;
ret = idmap_cache_find_sid2unixid ( sid , & id , expired ) ;
2008-07-08 00:09:39 +04:00
if ( ! ret ) {
return false ;
}
2012-03-23 14:01:01 +04:00
if ( id . type = = ID_TYPE_BOTH | | id . type = = ID_TYPE_UID ) {
* puid = id . id ;
} else {
* puid = - 1 ;
2008-07-08 00:09:39 +04:00
}
2012-03-23 14:01:01 +04:00
return true ;
2008-07-08 00:09:39 +04:00
}
2008-07-17 15:32:28 +04:00
/**
2012-03-23 14:01:01 +04:00
* Find a sid2gid mapping
2008-07-17 15:32:28 +04:00
* @ param [ in ] sid the sid to map
2012-03-23 14:01:01 +04:00
* @ param [ out ] pgid where to put the result
* @ param [ out ] expired is the cache entry expired ?
* @ retval Was anything in the cache at all ?
2008-07-17 15:32:28 +04:00
*
2012-03-23 14:01:01 +04:00
* If * pgid = = - 1 this was a negative mapping .
2008-07-17 15:32:28 +04:00
*/
2012-03-23 14:01:01 +04:00
bool idmap_cache_find_sid2gid ( const struct dom_sid * sid , gid_t * pgid ,
bool * expired )
2008-07-08 00:09:39 +04:00
{
2012-03-23 14:01:01 +04:00
bool ret ;
struct unixid id ;
ret = idmap_cache_find_sid2unixid ( sid , & id , expired ) ;
if ( ! ret ) {
return false ;
2008-07-08 00:09:39 +04:00
}
2012-03-23 14:01:01 +04:00
if ( id . type = = ID_TYPE_BOTH | | id . type = = ID_TYPE_GID ) {
* pgid = id . id ;
} else {
* pgid = - 1 ;
2008-07-08 00:09:39 +04:00
}
2012-03-23 14:01:01 +04:00
return true ;
2008-07-08 00:09:39 +04:00
}
2008-07-11 15:58:31 +04:00
2013-12-04 19:37:21 +04:00
struct idmap_cache_xid2sid_state {
struct dom_sid * sid ;
bool * expired ;
bool ret ;
} ;
static void idmap_cache_xid2sid_parser ( time_t timeout , DATA_BLOB blob ,
void * private_data )
{
struct idmap_cache_xid2sid_state * state =
( struct idmap_cache_xid2sid_state * ) private_data ;
char * value ;
ZERO_STRUCTP ( state - > sid ) ;
state - > ret = false ;
if ( ( blob . length = = 0 ) | | ( blob . data [ blob . length - 1 ] ! = 0 ) ) {
/*
* Not a string , can ' t be a valid mapping
*/
return ;
}
value = ( char * ) blob . data ;
if ( value [ 0 ] ! = ' - ' ) {
state - > ret = string_to_sid ( state - > sid , value ) ;
}
if ( state - > ret ) {
* state - > expired = ( timeout < = time ( NULL ) ) ;
}
}
2008-07-17 15:32:28 +04:00
/**
2012-03-23 14:01:01 +04:00
* Find a uid2sid mapping
* @ param [ in ] uid the uid to map
* @ param [ out ] sid where to put the result
2008-07-17 15:32:28 +04:00
* @ param [ out ] expired is the cache entry expired ?
* @ retval Was anything in the cache at all ?
*
2012-03-23 14:01:01 +04:00
* If " is_null_sid(sid) " , this was a negative mapping .
2008-07-17 15:32:28 +04:00
*/
2012-03-23 14:01:01 +04:00
bool idmap_cache_find_uid2sid ( uid_t uid , struct dom_sid * sid , bool * expired )
2008-07-11 15:58:31 +04:00
{
2013-12-04 19:14:03 +04:00
fstring key ;
2013-12-04 19:37:21 +04:00
struct idmap_cache_xid2sid_state state ;
2008-07-11 15:58:31 +04:00
2013-12-04 19:14:03 +04:00
fstr_sprintf ( key , " IDMAP/UID2SID/%d " , ( int ) uid ) ;
2013-12-04 19:37:21 +04:00
state . sid = sid ;
state . expired = expired ;
state . ret = false ;
gencache_parse ( key , idmap_cache_xid2sid_parser , & state ) ;
return state . ret ;
2008-07-11 15:58:31 +04:00
}
2008-07-17 15:32:28 +04:00
/**
* Find a gid2sid mapping
* @ param [ in ] gid the gid to map
* @ param [ out ] sid where to put the result
* @ param [ out ] expired is the cache entry expired ?
* @ retval Was anything in the cache at all ?
*
* If " is_null_sid(sid) " , this was a negative mapping .
*/
2008-07-11 15:58:31 +04:00
bool idmap_cache_find_gid2sid ( gid_t gid , struct dom_sid * sid , bool * expired )
{
2013-12-04 19:14:03 +04:00
fstring key ;
2013-12-04 19:37:21 +04:00
struct idmap_cache_xid2sid_state state ;
2008-07-11 15:58:31 +04:00
2013-12-04 19:14:03 +04:00
fstr_sprintf ( key , " IDMAP/GID2SID/%d " , ( int ) gid ) ;
2013-12-04 19:37:21 +04:00
state . sid = sid ;
state . expired = expired ;
state . ret = false ;
gencache_parse ( key , idmap_cache_xid2sid_parser , & state ) ;
return state . ret ;
2008-07-11 15:58:31 +04:00
}
2008-07-17 15:32:28 +04:00
/**
* Store a mapping in the idmap cache
* @ param [ in ] sid the sid to map
* @ param [ in ] gid the gid to map
*
* If both parameters are valid values , then a positive mapping in both
* directions is stored . If " is_null_sid(sid) " is true , then this will be a
* negative mapping of gid , we want to cache that for this gid we could not
* find anything . Likewise if " gid==-1 " , then we want to cache that we did not
* find a mapping for the sid passed here .
*/
2012-03-23 14:01:01 +04:00
void idmap_cache_set_sid2unixid ( const struct dom_sid * sid , struct unixid * unix_id )
2008-07-11 15:58:31 +04:00
{
time_t now = time ( NULL ) ;
time_t timeout ;
fstring sidstr , key , value ;
if ( ! is_null_sid ( sid ) ) {
2012-03-23 14:01:01 +04:00
fstr_sprintf ( key , " IDMAP/SID2XID/%s " ,
2008-07-11 15:58:31 +04:00
sid_to_fstring ( sidstr , sid ) ) ;
2012-03-23 14:01:01 +04:00
switch ( unix_id - > type ) {
case ID_TYPE_UID :
fstr_sprintf ( value , " %d:U " , ( int ) unix_id - > id ) ;
break ;
case ID_TYPE_GID :
fstr_sprintf ( value , " %d:G " , ( int ) unix_id - > id ) ;
break ;
case ID_TYPE_BOTH :
fstr_sprintf ( value , " %d:B " , ( int ) unix_id - > id ) ;
break ;
2012-06-20 16:07:51 +04:00
case ID_TYPE_NOT_SPECIFIED :
fstr_sprintf ( value , " %d:N " , ( int ) unix_id - > id ) ;
break ;
2012-03-23 14:01:01 +04:00
default :
return ;
}
timeout = ( unix_id - > id = = - 1 )
2008-07-11 15:58:31 +04:00
? lp_idmap_negative_cache_time ( )
: lp_idmap_cache_time ( ) ;
gencache_set ( key , value , now + timeout ) ;
}
2012-03-23 14:01:01 +04:00
if ( unix_id - > id ! = - 1 ) {
2008-07-13 14:07:40 +04:00
if ( is_null_sid ( sid ) ) {
/* negative gid mapping */
fstrcpy ( value , " - " ) ;
timeout = lp_idmap_negative_cache_time ( ) ;
}
else {
sid_to_fstring ( value , sid ) ;
timeout = lp_idmap_cache_time ( ) ;
}
2012-03-23 14:01:01 +04:00
switch ( unix_id - > type ) {
case ID_TYPE_BOTH :
fstr_sprintf ( key , " IDMAP/UID2SID/%d " , ( int ) unix_id - > id ) ;
gencache_set ( key , value , now + timeout ) ;
fstr_sprintf ( key , " IDMAP/GID2SID/%d " , ( int ) unix_id - > id ) ;
gencache_set ( key , value , now + timeout ) ;
return ;
case ID_TYPE_UID :
fstr_sprintf ( key , " IDMAP/UID2SID/%d " , ( int ) unix_id - > id ) ;
break ;
case ID_TYPE_GID :
fstr_sprintf ( key , " IDMAP/GID2SID/%d " , ( int ) unix_id - > id ) ;
break ;
default :
return ;
}
2008-07-11 15:58:31 +04:00
gencache_set ( key , value , now + timeout ) ;
}
}
2011-02-18 16:47:03 +03:00
static char * key_xid2sid_str ( TALLOC_CTX * mem_ctx , char t , const char * id ) {
return talloc_asprintf ( mem_ctx , " IDMAP/%cID2SID/%s " , t , id ) ;
}
static char * key_xid2sid ( TALLOC_CTX * mem_ctx , char t , int id ) {
char str [ 32 ] ;
snprintf ( str , sizeof ( str ) , " %d " , id ) ;
return key_xid2sid_str ( mem_ctx , t , str ) ;
}
2012-03-23 14:01:01 +04:00
static char * key_sid2xid_str ( TALLOC_CTX * mem_ctx , const char * id ) {
return talloc_asprintf ( mem_ctx , " IDMAP/SID2XID/%s " , id ) ;
2011-02-18 16:47:03 +03:00
}
static bool idmap_cache_del_xid ( char t , int xid )
{
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
const char * key = key_xid2sid ( mem_ctx , t , xid ) ;
char * sid_str = NULL ;
time_t timeout ;
bool ret = true ;
2013-09-04 10:57:59 +04:00
if ( ! gencache_get ( key , mem_ctx , & sid_str , & timeout ) ) {
2011-03-01 19:18:31 +03:00
DEBUG ( 3 , ( " no entry: %s \n " , key ) ) ;
2011-03-02 15:58:37 +03:00
ret = false ;
2011-02-18 16:47:03 +03:00
goto done ;
}
if ( sid_str [ 0 ] ! = ' - ' ) {
2012-03-23 14:01:01 +04:00
const char * sid_key = key_sid2xid_str ( mem_ctx , sid_str ) ;
2011-02-18 16:47:03 +03:00
if ( ! gencache_del ( sid_key ) ) {
2011-03-01 19:18:31 +03:00
DEBUG ( 2 , ( " failed to delete: %s \n " , sid_key ) ) ;
2011-02-18 16:47:03 +03:00
ret = false ;
} else {
2011-03-01 19:18:31 +03:00
DEBUG ( 5 , ( " delete: %s \n " , sid_key ) ) ;
2011-02-18 16:47:03 +03:00
}
}
if ( ! gencache_del ( key ) ) {
2011-03-01 19:18:31 +03:00
DEBUG ( 1 , ( " failed to delete: %s \n " , key ) ) ;
2011-02-18 16:47:03 +03:00
ret = false ;
} else {
2011-03-01 19:18:31 +03:00
DEBUG ( 5 , ( " delete: %s \n " , key ) ) ;
2011-02-18 16:47:03 +03:00
}
done :
talloc_free ( mem_ctx ) ;
return ret ;
}
bool idmap_cache_del_uid ( uid_t uid ) {
return idmap_cache_del_xid ( ' U ' , uid ) ;
}
bool idmap_cache_del_gid ( gid_t gid ) {
return idmap_cache_del_xid ( ' G ' , gid ) ;
}
2012-03-23 14:01:01 +04:00
bool idmap_cache_del_sid ( const struct dom_sid * sid )
2011-02-18 16:47:03 +03:00
{
2012-03-23 14:01:01 +04:00
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2011-02-18 16:47:03 +03:00
bool ret = true ;
2012-03-23 14:01:01 +04:00
bool expired ;
struct unixid id ;
const char * sid_key ;
2011-02-18 16:47:03 +03:00
2012-03-23 14:01:01 +04:00
if ( ! idmap_cache_find_sid2unixid ( sid , & id , & expired ) ) {
2011-02-18 16:47:03 +03:00
ret = false ;
goto done ;
}
2012-03-23 14:01:01 +04:00
if ( id . id ! = - 1 ) {
switch ( id . type ) {
case ID_TYPE_BOTH :
idmap_cache_del_xid ( ' U ' , id . id ) ;
idmap_cache_del_xid ( ' G ' , id . id ) ;
break ;
case ID_TYPE_UID :
idmap_cache_del_xid ( ' U ' , id . id ) ;
break ;
case ID_TYPE_GID :
idmap_cache_del_xid ( ' G ' , id . id ) ;
break ;
default :
break ;
2011-02-18 16:47:03 +03:00
}
}
2012-03-23 14:01:01 +04:00
sid_key = key_sid2xid_str ( mem_ctx , dom_sid_string ( mem_ctx , sid ) ) ;
if ( sid_key = = NULL ) {
return false ;
2011-02-18 16:47:03 +03:00
}
2012-03-23 14:01:01 +04:00
/* If the mapping was symmetric, then this should fail */
gencache_del ( sid_key ) ;
2011-02-18 16:47:03 +03:00
done :
talloc_free ( mem_ctx ) ;
return ret ;
}