2002-09-11 18:07:21 +04:00
/*
Unix SMB / CIFS implementation .
Generic , persistent and shared between processes cache mechanism for use
by various parts of the Samba code
Copyright ( C ) Rafal Szczesniak 2002
2009-09-20 20:10:01 +04:00
Copyright ( C ) Volker Lendecke 2009
2009-01-19 02:01:08 +03:00
2002-09-11 18:07:21 +04: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
2002-09-11 18:07:21 +04:00
( at your option ) any later version .
2009-01-19 02:01:08 +03:00
2002-09-11 18:07:21 +04: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 .
2009-01-19 02:01:08 +03:00
2002-09-11 18:07:21 +04: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/>.
2002-09-11 18:07:21 +04:00
*/
# include "includes.h"
2018-10-18 22:53:36 +03:00
# include "lib/gencache.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-02-25 18:34:46 +03:00
# include "system/glob.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2014-11-18 00:30:49 +03:00
# include "tdb_wrap/tdb_wrap.h"
2018-10-10 17:53:10 +03:00
# include "zlib.h"
2018-10-24 11:51:40 +03:00
# include "lib/util/strv.h"
2020-05-06 18:10:51 +03:00
# include "lib/util/util_paths.h"
2002-09-11 18:07:21 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_TDB
2020-05-06 18:10:51 +03:00
# define GENCACHE_USER_PATH "~ / .cache / samba / gencache.tdb"
2014-11-18 01:44:47 +03:00
static struct tdb_wrap * cache ;
2002-09-11 18:07:21 +04:00
/**
* @ file gencache . c
* @ brief Generic , persistent and shared between processes cache mechanism
* for use by various parts of the Samba code
*
* */
2018-10-24 11:51:40 +03:00
static bool gencache_pull_timeout ( TDB_DATA key ,
TDB_DATA data ,
time_t * pres ,
DATA_BLOB * payload ) ;
2018-10-13 14:41:59 +03:00
struct gencache_timeout {
time_t timeout ;
} ;
bool gencache_timeout_expired ( const struct gencache_timeout * t )
{
return t - > timeout < = time ( NULL ) ;
}
2002-09-11 18:07:21 +04:00
/**
* Cache initialisation function . Opens cache tdb file or creates
* it if does not exist .
*
* @ return true on successful initialisation of the cache or
* false on failure
* */
2009-07-10 14:24:56 +04:00
static bool gencache_init ( void )
2002-09-11 18:07:21 +04:00
{
char * cache_fname = NULL ;
2009-07-13 19:04:29 +04:00
int open_flags = O_RDWR | O_CREAT ;
2020-05-06 18:10:51 +03:00
int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_NOSYNC | TDB_MUTEX_LOCKING ;
2017-02-06 19:10:40 +03:00
int hash_size ;
2009-01-19 02:01:08 +03:00
2002-09-11 18:07:21 +04:00
/* skip file open if it's already opened */
2015-12-13 17:17:27 +03:00
if ( cache ) {
return true ;
}
2002-09-11 18:07:21 +04:00
2017-02-06 19:10:40 +03:00
hash_size = lp_parm_int ( - 1 , " gencache " , " hash_size " , 10000 ) ;
2018-10-11 13:52:40 +03:00
cache_fname = lock_path ( talloc_tos ( ) , " gencache.tdb " ) ;
2014-10-06 20:21:13 +04:00
if ( cache_fname = = NULL ) {
return false ;
}
2002-09-11 18:07:21 +04:00
2006-09-10 01:05:51 +04:00
DEBUG ( 5 , ( " Opening cache file at %s \n " , cache_fname ) ) ;
2017-02-06 19:10:40 +03:00
cache = tdb_wrap_open ( NULL , cache_fname , hash_size ,
2020-05-06 18:10:51 +03:00
tdb_flags ,
2014-11-18 01:44:47 +03:00
open_flags , 0644 ) ;
2020-05-06 18:10:51 +03:00
/*
* Allow client tools to create a gencache in the home directory
* as a normal user .
*/
if ( cache = = NULL & & errno = = EACCES & & geteuid ( ) ! = 0 ) {
char * cache_dname = NULL , * tmp = NULL ;
bool ok ;
TALLOC_FREE ( cache_fname ) ;
cache_fname = path_expand_tilde ( talloc_tos ( ) ,
GENCACHE_USER_PATH ) ;
if ( cache_fname = = NULL ) {
DBG_ERR ( " Failed to expand path: %s \n " ,
GENCACHE_USER_PATH ) ;
return false ;
}
tmp = talloc_strdup ( talloc_tos ( ) , cache_fname ) ;
if ( tmp = = NULL ) {
DBG_ERR ( " No memory! \n " ) ;
TALLOC_FREE ( cache_fname ) ;
return false ;
}
cache_dname = dirname ( tmp ) ;
if ( cache_dname = = NULL ) {
DBG_ERR ( " Invalid path: %s \n " , cache_fname ) ;
TALLOC_FREE ( tmp ) ;
TALLOC_FREE ( cache_fname ) ;
return false ;
}
2020-12-21 12:36:46 +03:00
ok = directory_create_or_exists_recursive ( cache_dname , 0700 ) ;
2020-05-06 18:10:51 +03:00
if ( ! ok ) {
DBG_ERR ( " Failed to create directory: %s - %s \n " ,
cache_dname , strerror ( errno ) ) ;
TALLOC_FREE ( tmp ) ;
TALLOC_FREE ( cache_fname ) ;
return false ;
}
TALLOC_FREE ( tmp ) ;
cache = tdb_wrap_open ( NULL ,
cache_fname ,
hash_size ,
tdb_flags ,
open_flags ,
0644 ) ;
if ( cache ! = NULL ) {
DBG_INFO ( " Opening user cache file %s. \n " ,
cache_fname ) ;
}
}
2018-10-11 13:52:40 +03:00
if ( cache = = NULL ) {
2009-07-13 19:04:29 +04:00
DEBUG ( 5 , ( " Opening %s failed: %s \n " , cache_fname ,
strerror ( errno ) ) ) ;
2014-10-06 20:21:13 +04:00
TALLOC_FREE ( cache_fname ) ;
2009-07-13 19:04:29 +04:00
return false ;
}
2014-10-06 20:21:13 +04:00
TALLOC_FREE ( cache_fname ) ;
2009-07-13 19:04:29 +04:00
2015-12-13 17:17:27 +03:00
return true ;
2002-09-11 18:07:21 +04:00
}
2018-10-24 11:51:40 +03:00
/*
* Walk the hash chain for " key " , deleting all expired entries for
* that hash chain
*/
struct gencache_prune_expired_state {
TALLOC_CTX * mem_ctx ;
char * keys ;
} ;
static int gencache_prune_expired_fn ( struct tdb_context * tdb ,
TDB_DATA key ,
TDB_DATA data ,
void * private_data )
{
struct gencache_prune_expired_state * state = private_data ;
struct gencache_timeout t ;
bool ok = false ;
bool expired = false ;
if ( ( key . dsize = = 0 ) | | ( key . dptr [ key . dsize - 1 ] ! = ' \0 ' ) ) {
/* not a valid record, should never happen */
return 0 ;
}
ok = gencache_pull_timeout ( key , data , & t . timeout , NULL ) ;
if ( ok ) {
expired = gencache_timeout_expired ( & t ) ;
}
if ( ! ok | | expired ) {
2018-11-14 23:02:01 +03:00
int ret ;
ret = strv_add ( state - > mem_ctx , & state - > keys , ( char * ) key . dptr ) ;
if ( ret ! = 0 ) {
/*
* Exit the loop . It ' s unlikely that it will
* succeed next time .
*/
return - 1 ;
}
2018-10-24 11:51:40 +03:00
}
return 0 ;
}
static void gencache_prune_expired ( struct tdb_context * tdb ,
TDB_DATA chain_key )
{
struct gencache_prune_expired_state state = {
. mem_ctx = talloc_tos ( ) ,
} ;
char * keystr = NULL ;
int ret ;
ret = tdb_traverse_key_chain (
tdb , chain_key , gencache_prune_expired_fn , & state ) ;
if ( ret = = - 1 ) {
DBG_DEBUG ( " tdb_traverse_key_chain failed: %s \n " ,
tdb_errorstr ( tdb ) ) ;
return ;
}
while ( ( keystr = strv_next ( state . keys , keystr ) ) ! = NULL ) {
TDB_DATA key = string_term_tdb_data ( keystr ) ;
/*
* We expect the hash chain of " chain_key " to be
* locked . So between gencache_prune_expired_fn
* figuring out " keystr " is expired and the
* tdb_delete , nobody can have reset the timeout .
*/
tdb_delete ( tdb , key ) ;
}
TALLOC_FREE ( state . keys ) ;
}
2002-09-11 18:07:21 +04:00
/**
2003-01-04 11:48:15 +03:00
* Set an entry in the cache file . If there ' s no such
* one , then add it .
2002-09-11 18:07:21 +04:00
*
2003-04-14 06:18:10 +04:00
* @ param keystr string that represents a key of this entry
2009-07-14 13:33:04 +04:00
* @ param blob DATA_BLOB value being cached
2002-09-11 18:07:21 +04:00
* @ param timeout time when the value is expired
*
2015-04-28 09:38:43 +03:00
* @ retval true when entry is successfully stored
2003-04-14 06:18:10 +04:00
* @ retval false on failure
2002-09-11 18:07:21 +04:00
* */
2009-01-19 02:01:08 +03:00
2017-08-02 18:52:40 +03:00
bool gencache_set_data_blob ( const char * keystr , DATA_BLOB blob ,
2009-07-14 13:33:04 +04:00
time_t timeout )
2002-09-11 18:07:21 +04:00
{
2018-10-09 14:17:53 +03:00
TDB_DATA key ;
2002-09-11 18:07:21 +04:00
int ret ;
2018-10-10 17:53:10 +03:00
TDB_DATA dbufs [ 3 ] ;
uint32_t crc ;
2009-07-13 19:04:29 +04:00
2018-10-09 14:15:22 +03:00
if ( ( keystr = = NULL ) | | ( blob . data = = NULL ) ) {
2009-07-13 19:04:29 +04:00
return false ;
}
2009-01-19 02:01:08 +03:00
2018-10-09 14:17:53 +03:00
key = string_term_tdb_data ( keystr ) ;
2015-12-13 17:17:27 +03:00
if ( ! gencache_init ( ) ) {
return false ;
}
2009-01-19 02:01:08 +03:00
2018-10-10 17:12:28 +03:00
dbufs [ 0 ] = ( TDB_DATA ) { . dptr = ( uint8_t * ) & timeout ,
. dsize = sizeof ( time_t ) } ;
2017-08-02 18:52:40 +03:00
dbufs [ 1 ] = ( TDB_DATA ) { . dptr = blob . data , . dsize = blob . length } ;
2015-12-13 23:16:36 +03:00
2018-10-10 17:53:10 +03:00
crc = crc32 ( 0 , Z_NULL , 0 ) ;
crc = crc32 ( crc , key . dptr , key . dsize ) ;
crc = crc32 ( crc , dbufs [ 0 ] . dptr , dbufs [ 0 ] . dsize ) ;
crc = crc32 ( crc , dbufs [ 1 ] . dptr , dbufs [ 1 ] . dsize ) ;
dbufs [ 2 ] = ( TDB_DATA ) { . dptr = ( uint8_t * ) & crc ,
. dsize = sizeof ( crc ) } ;
2019-01-17 15:58:14 +03:00
DBG_DEBUG ( " Adding cache entry with key=[%s] and timeout= "
" [%s] (%ld seconds %s) \n " , keystr ,
2013-02-13 12:46:33 +04:00
timestring ( talloc_tos ( ) , timeout ) ,
2019-01-17 15:58:14 +03:00
( ( long int ) timeout ) - time ( NULL ) ,
timeout > time ( NULL ) ? " ahead " : " in the past " ) ;
2003-09-08 05:28:48 +04:00
2018-10-24 11:51:40 +03:00
ret = tdb_chainlock ( cache - > tdb , key ) ;
if ( ret = = - 1 ) {
DBG_WARNING ( " tdb_chainlock for key [%s] failed: %s \n " ,
keystr , tdb_errorstr ( cache - > tdb ) ) ;
return false ;
}
gencache_prune_expired ( cache - > tdb , key ) ;
2018-10-11 13:52:40 +03:00
ret = tdb_storev ( cache - > tdb , key , dbufs , ARRAY_SIZE ( dbufs ) , 0 ) ;
2009-07-13 19:04:29 +04:00
2018-10-24 11:51:40 +03:00
tdb_chainunlock ( cache - > tdb , key ) ;
2018-11-02 18:58:53 +03:00
if ( ret = = 0 ) {
return true ;
}
if ( tdb_error ( cache - > tdb ) ! = TDB_ERR_CORRUPT ) {
return false ;
}
ret = tdb_wipe_all ( cache - > tdb ) ;
SMB_ASSERT ( ret = = 0 ) ;
return false ;
2002-09-11 18:07:21 +04:00
}
/**
* Delete one entry from the cache file .
*
2003-04-14 06:18:10 +04:00
* @ param keystr string that represents a key of this entry
2002-09-11 18:07:21 +04:00
*
2003-04-14 06:18:10 +04:00
* @ retval true upon successful deletion
* @ retval false in case of failure
2002-09-11 18:07:21 +04:00
* */
2007-10-19 04:40:25 +04:00
bool gencache_del ( const char * keystr )
2002-09-11 18:07:21 +04:00
{
2016-03-03 17:59:05 +03:00
TDB_DATA key = string_term_tdb_data ( keystr ) ;
int ret ;
2009-01-19 02:01:08 +03:00
2009-07-10 12:54:33 +04:00
if ( keystr = = NULL ) {
return false ;
}
2002-09-11 18:07:21 +04:00
2015-12-13 17:17:27 +03:00
if ( ! gencache_init ( ) ) {
return false ;
}
2009-01-19 02:01:08 +03:00
2013-02-11 16:43:32 +04:00
DEBUG ( 10 , ( " Deleting cache entry (key=[%s]) \n " , keystr ) ) ;
2009-01-19 02:01:08 +03:00
2018-10-11 13:52:40 +03:00
ret = tdb_delete ( cache - > tdb , key ) ;
2016-03-03 17:59:05 +03:00
2018-11-02 18:58:53 +03:00
if ( ret = = 0 ) {
return true ;
}
if ( tdb_error ( cache - > tdb ) ! = TDB_ERR_CORRUPT ) {
return false ;
}
ret = tdb_wipe_all ( cache - > tdb ) ;
SMB_ASSERT ( ret = = 0 ) ;
return true ; /* We've deleted a bit more... */
2002-09-11 18:07:21 +04:00
}
2018-10-10 17:53:10 +03:00
static bool gencache_pull_timeout ( TDB_DATA key ,
TDB_DATA data ,
time_t * pres ,
DATA_BLOB * payload )
2009-07-13 19:04:29 +04:00
{
2018-10-10 17:53:10 +03:00
size_t crc_ofs ;
uint32_t crc , stored_crc ;
if ( ( data . dptr = = NULL ) | |
( data . dsize < ( sizeof ( time_t ) + sizeof ( uint32_t ) ) ) ) {
return false ;
}
crc_ofs = data . dsize - sizeof ( uint32_t ) ;
crc = crc32 ( 0 , Z_NULL , 0 ) ;
crc = crc32 ( crc , key . dptr , key . dsize ) ;
crc = crc32 ( crc , data . dptr , crc_ofs ) ;
memcpy ( & stored_crc , data . dptr + crc_ofs , sizeof ( uint32_t ) ) ;
if ( stored_crc ! = crc ) {
2009-07-13 19:04:29 +04:00
return false ;
}
2018-10-10 17:53:10 +03:00
2009-07-13 19:04:29 +04:00
if ( pres ! = NULL ) {
2018-10-10 17:12:28 +03:00
memcpy ( pres , data . dptr , sizeof ( time_t ) ) ;
2009-07-13 19:04:29 +04:00
}
2015-07-22 17:03:47 +03:00
if ( payload ! = NULL ) {
2018-10-09 14:58:43 +03:00
* payload = ( DATA_BLOB ) {
2018-10-10 17:53:10 +03:00
. data = data . dptr + sizeof ( time_t ) ,
. length = data . dsize - sizeof ( time_t ) - sizeof ( uint32_t ) ,
2018-10-09 14:58:43 +03:00
} ;
2009-07-13 19:04:29 +04:00
}
return true ;
}
2002-09-11 18:07:21 +04:00
2010-11-27 02:40:25 +03:00
struct gencache_parse_state {
2018-10-13 14:41:59 +03:00
void ( * parser ) ( const struct gencache_timeout * timeout ,
DATA_BLOB blob ,
void * private_data ) ;
2010-11-27 02:40:25 +03:00
void * private_data ;
2018-11-02 18:58:53 +03:00
bool format_error ;
2010-11-27 02:40:25 +03:00
} ;
static int gencache_parse_fn ( TDB_DATA key , TDB_DATA data , void * private_data )
{
2018-11-02 18:58:53 +03:00
struct gencache_parse_state * state = private_data ;
2018-10-13 14:41:59 +03:00
struct gencache_timeout t ;
2018-10-09 14:58:43 +03:00
DATA_BLOB payload ;
2010-11-27 02:40:25 +03:00
bool ret ;
2018-10-10 17:53:10 +03:00
ret = gencache_pull_timeout ( key , data , & t . timeout , & payload ) ;
2010-11-27 02:40:25 +03:00
if ( ! ret ) {
2018-11-02 18:58:53 +03:00
state - > format_error = true ;
return 0 ;
2010-11-27 02:40:25 +03:00
}
2018-10-09 14:58:43 +03:00
state - > parser ( & t , payload , state - > private_data ) ;
2014-03-10 18:41:32 +04:00
2010-11-27 02:40:25 +03:00
return 0 ;
}
bool gencache_parse ( const char * keystr ,
2018-10-13 14:41:59 +03:00
void ( * parser ) ( const struct gencache_timeout * timeout ,
DATA_BLOB blob ,
2010-11-27 02:40:25 +03:00
void * private_data ) ,
void * private_data )
{
2018-11-02 18:58:53 +03:00
struct gencache_parse_state state = {
. parser = parser , . private_data = private_data
} ;
2013-09-08 15:29:33 +04:00
TDB_DATA key = string_term_tdb_data ( keystr ) ;
2010-11-27 02:40:25 +03:00
int ret ;
if ( keystr = = NULL ) {
return false ;
}
if ( ! gencache_init ( ) ) {
return false ;
}
2018-10-11 13:52:40 +03:00
ret = tdb_parse_record ( cache - > tdb , key ,
2014-11-18 00:30:49 +03:00
gencache_parse_fn , & state ) ;
2018-11-02 18:58:53 +03:00
if ( ( ret = = - 1 ) & & ( tdb_error ( cache - > tdb ) = = TDB_ERR_CORRUPT ) ) {
goto wipe ;
}
if ( ret = = - 1 ) {
return false ;
}
if ( state . format_error ) {
ret = tdb_delete ( cache - > tdb , key ) ;
if ( ret = = - 1 ) {
goto wipe ;
}
return false ;
2010-11-27 02:40:25 +03:00
}
2018-11-02 18:58:53 +03:00
return true ;
2016-03-03 19:41:34 +03:00
2018-11-02 18:58:53 +03:00
wipe :
ret = tdb_wipe_all ( cache - > tdb ) ;
SMB_ASSERT ( ret = = 0 ) ;
return false ;
2010-11-27 02:40:25 +03:00
}
2010-11-27 13:36:52 +03:00
struct gencache_get_data_blob_state {
2013-09-04 10:22:43 +04:00
TALLOC_CTX * mem_ctx ;
2010-11-27 13:36:52 +03:00
DATA_BLOB * blob ;
time_t timeout ;
bool result ;
} ;
2018-10-13 14:41:59 +03:00
static void gencache_get_data_blob_parser ( const struct gencache_timeout * t ,
DATA_BLOB blob ,
2010-11-27 13:36:52 +03:00
void * private_data )
{
struct gencache_get_data_blob_state * state =
( struct gencache_get_data_blob_state * ) private_data ;
2018-10-13 14:41:59 +03:00
if ( t - > timeout = = 0 ) {
2010-11-27 13:36:52 +03:00
state - > result = false ;
return ;
}
2018-10-13 14:41:59 +03:00
state - > timeout = t - > timeout ;
2010-11-27 13:36:52 +03:00
if ( state - > blob = = NULL ) {
state - > result = true ;
return ;
}
2013-09-04 10:22:43 +04:00
* state - > blob = data_blob_talloc ( state - > mem_ctx , blob . data ,
blob . length ) ;
2010-11-27 13:36:52 +03:00
if ( state - > blob - > data = = NULL ) {
state - > result = false ;
return ;
}
state - > result = true ;
}
2002-09-11 18:07:21 +04:00
/**
* Get existing entry from the cache file .
*
2003-04-14 06:18:10 +04:00
* @ param keystr string that represents a key of this entry
2009-07-14 13:33:04 +04:00
* @ param blob DATA_BLOB that is filled with entry ' s blob
2008-07-11 19:44:15 +04:00
* @ param timeout pointer to a time_t that is filled with entry ' s
* timeout
2002-09-11 18:07:21 +04:00
*
2017-02-17 22:51:29 +03:00
* @ retval true when entry is successfully fetched
2015-12-13 17:17:27 +03:00
* @ retval false for failure
2002-09-11 18:07:21 +04:00
* */
2013-09-04 10:22:43 +04:00
bool gencache_get_data_blob ( const char * keystr , TALLOC_CTX * mem_ctx ,
DATA_BLOB * blob ,
2009-09-23 17:21:40 +04:00
time_t * timeout , bool * was_expired )
2002-09-11 18:07:21 +04:00
{
2010-11-27 13:36:52 +03:00
struct gencache_get_data_blob_state state ;
2009-09-23 17:21:40 +04:00
bool expired = false ;
2002-09-11 18:07:21 +04:00
2010-11-27 13:36:52 +03:00
state . result = false ;
2013-09-04 10:22:43 +04:00
state . mem_ctx = mem_ctx ;
2010-11-27 13:36:52 +03:00
state . blob = blob ;
2009-07-13 19:04:29 +04:00
2010-11-27 13:36:52 +03:00
if ( ! gencache_parse ( keystr , gencache_get_data_blob_parser , & state ) ) {
2009-09-23 17:21:40 +04:00
goto fail ;
2006-09-10 01:31:56 +04:00
}
2010-11-27 13:36:52 +03:00
if ( ! state . result ) {
2009-09-23 17:21:40 +04:00
goto fail ;
2006-09-10 01:31:56 +04:00
}
2010-11-27 13:36:52 +03:00
if ( state . timeout < = time ( NULL ) ) {
2009-07-13 19:04:29 +04:00
/*
* We ' re expired , delete the entry . We can ' t use gencache_del
* here , because that uses gencache_get_data_blob for checking
* the existence of a record . We know the thing exists and
* directly store an empty value with 0 timeout .
*/
gencache_set ( keystr , " " , 0 ) ;
2009-09-23 17:21:40 +04:00
expired = true ;
goto fail ;
2006-09-10 01:40:47 +04:00
}
2008-07-11 19:44:15 +04:00
if ( timeout ) {
2010-11-27 13:36:52 +03:00
* timeout = state . timeout ;
2006-06-16 01:03:40 +04:00
}
2003-01-25 00:25:12 +03:00
2015-12-13 17:17:27 +03:00
return true ;
2009-09-23 17:21:40 +04:00
fail :
if ( was_expired ! = NULL ) {
* was_expired = expired ;
}
2010-12-17 15:26:16 +03:00
if ( state . result & & state . blob ) {
data_blob_free ( state . blob ) ;
}
2009-09-23 17:21:40 +04:00
return false ;
2008-07-11 19:44:15 +04:00
}
2006-09-10 01:31:56 +04:00
2007-08-28 16:40:01 +04:00
/**
* Get existing entry from the cache file .
*
* @ param keystr string that represents a key of this entry
2009-07-14 13:33:04 +04:00
* @ param valstr buffer that is allocated and filled with the entry value
* buffer ' s disposing must be done outside
* @ param timeout pointer to a time_t that is filled with entry ' s
* timeout
2007-08-28 16:40:01 +04:00
*
2016-03-06 12:27:06 +03:00
* @ retval true when entry is successfully fetched
2015-12-13 17:17:27 +03:00
* @ retval false for failure
2007-08-28 16:40:01 +04:00
* */
2013-09-04 10:56:23 +04:00
bool gencache_get ( const char * keystr , TALLOC_CTX * mem_ctx , char * * value ,
time_t * ptimeout )
2007-08-28 16:40:01 +04:00
{
2009-07-14 13:33:04 +04:00
DATA_BLOB blob ;
2015-12-13 17:17:27 +03:00
bool ret = false ;
2007-08-28 16:40:01 +04:00
2013-09-04 10:57:59 +04:00
ret = gencache_get_data_blob ( keystr , mem_ctx , & blob , ptimeout , NULL ) ;
2009-07-14 13:33:04 +04:00
if ( ! ret ) {
2009-07-10 12:54:33 +04:00
return false ;
}
2009-07-14 13:33:04 +04:00
if ( ( blob . data = = NULL ) | | ( blob . length = = 0 ) ) {
2013-09-04 10:46:34 +04:00
data_blob_free ( & blob ) ;
2009-07-14 13:33:04 +04:00
return false ;
2007-08-28 16:40:01 +04:00
}
2009-07-14 13:33:04 +04:00
if ( blob . data [ blob . length - 1 ] ! = ' \0 ' ) {
/* Not NULL terminated, can't be a string */
2013-09-04 10:46:34 +04:00
data_blob_free ( & blob ) ;
2009-07-14 13:33:04 +04:00
return false ;
2007-08-28 16:40:01 +04:00
}
2009-11-02 15:01:58 +03:00
if ( value ) {
2013-12-16 15:42:46 +04:00
/*
* talloc_move generates a type - punned warning here . As we
* leave the function immediately , do a simple talloc_steal .
*/
* value = ( char * ) talloc_steal ( mem_ctx , blob . data ) ;
2009-11-02 15:01:58 +03:00
return true ;
2007-08-28 16:40:01 +04:00
}
2009-11-02 15:01:58 +03:00
data_blob_free ( & blob ) ;
2009-07-14 13:33:04 +04:00
return true ;
2007-08-28 16:40:01 +04:00
}
/**
* Set an entry in the cache file . If there ' s no such
* one , then add it .
*
* @ param keystr string that represents a key of this entry
2009-07-14 13:33:04 +04:00
* @ param value text representation value being cached
2007-08-28 16:40:01 +04:00
* @ param timeout time when the value is expired
*
2017-02-17 22:51:29 +03:00
* @ retval true when entry is successfully stored
2007-08-28 16:40:01 +04:00
* @ retval false on failure
* */
2009-07-14 13:33:04 +04:00
bool gencache_set ( const char * keystr , const char * value , time_t timeout )
2007-08-28 16:40:01 +04:00
{
2009-07-14 13:33:04 +04:00
DATA_BLOB blob = data_blob_const ( value , strlen ( value ) + 1 ) ;
2017-08-02 18:52:40 +03:00
return gencache_set_data_blob ( keystr , blob , timeout ) ;
2007-08-28 16:40:01 +04:00
}
2002-09-11 18:07:21 +04:00
2010-11-27 17:48:21 +03:00
struct gencache_iterate_blobs_state {
void ( * fn ) ( const char * key , DATA_BLOB value ,
time_t timeout , void * private_data ) ;
2009-01-19 02:01:08 +03:00
const char * pattern ;
2010-11-27 17:48:21 +03:00
void * private_data ;
2009-01-19 02:01:08 +03:00
} ;
2010-11-27 17:48:21 +03:00
static int gencache_iterate_blobs_fn ( struct tdb_context * tdb , TDB_DATA key ,
TDB_DATA data , void * priv )
2009-01-19 02:01:08 +03:00
{
2010-11-27 17:48:21 +03:00
struct gencache_iterate_blobs_state * state =
( struct gencache_iterate_blobs_state * ) priv ;
2009-01-19 02:01:08 +03:00
char * keystr ;
char * free_key = NULL ;
time_t timeout ;
2018-10-09 14:58:43 +03:00
DATA_BLOB payload ;
2009-01-19 02:01:08 +03:00
if ( key . dptr [ key . dsize - 1 ] = = ' \0 ' ) {
keystr = ( char * ) key . dptr ;
} else {
/* ensure 0-termination */
2013-09-04 10:57:59 +04:00
keystr = talloc_strndup ( talloc_tos ( ) , ( char * ) key . dptr , key . dsize ) ;
2009-01-19 02:01:08 +03:00
free_key = keystr ;
2013-09-04 10:57:59 +04:00
if ( keystr = = NULL ) {
goto done ;
}
2009-01-19 02:01:08 +03:00
}
2018-10-10 17:53:10 +03:00
if ( ! gencache_pull_timeout ( key , data , & timeout , & payload ) ) {
2009-01-19 02:01:08 +03:00
goto done ;
}
2016-03-03 17:59:05 +03:00
if ( timeout = = 0 ) {
/* delete marker */
goto done ;
}
2009-01-19 02:01:08 +03:00
if ( fnmatch ( state - > pattern , keystr , 0 ) ! = 0 ) {
goto done ;
}
2013-02-11 16:42:28 +04:00
DEBUG ( 10 , ( " Calling function with arguments "
" (key=[%s], timeout=[%s]) \n " ,
2013-02-13 12:43:19 +04:00
keystr , timestring ( talloc_tos ( ) , timeout ) ) ) ;
2009-01-19 02:01:08 +03:00
2018-10-09 14:58:43 +03:00
state - > fn ( keystr , payload , timeout , state - > private_data ) ;
2009-01-19 02:01:08 +03:00
done :
2013-09-04 10:57:59 +04:00
TALLOC_FREE ( free_key ) ;
2009-01-19 02:01:08 +03:00
return 0 ;
}
2010-11-27 17:48:21 +03:00
void gencache_iterate_blobs ( void ( * fn ) ( const char * key , DATA_BLOB value ,
time_t timeout , void * private_data ) ,
void * private_data , const char * pattern )
2002-09-11 18:07:21 +04:00
{
2010-11-27 17:48:21 +03:00
struct gencache_iterate_blobs_state state ;
2018-11-02 18:58:53 +03:00
int ret ;
2002-09-11 18:07:21 +04:00
2010-11-27 17:48:21 +03:00
if ( ( fn = = NULL ) | | ( pattern = = NULL ) | | ! gencache_init ( ) ) {
2009-07-10 12:54:33 +04:00
return ;
}
2002-09-11 18:07:21 +04:00
2010-11-27 17:48:21 +03:00
DEBUG ( 5 , ( " Searching cache keys with pattern %s \n " , pattern ) ) ;
2006-06-16 01:03:40 +04:00
2009-01-19 02:01:08 +03:00
state . fn = fn ;
2010-11-27 17:48:21 +03:00
state . pattern = pattern ;
state . private_data = private_data ;
2009-07-13 19:04:29 +04:00
2018-11-02 18:58:53 +03:00
ret = tdb_traverse ( cache - > tdb , gencache_iterate_blobs_fn , & state ) ;
if ( ( ret = = - 1 ) & & ( tdb_error ( cache - > tdb ) = = TDB_ERR_CORRUPT ) ) {
ret = tdb_wipe_all ( cache - > tdb ) ;
SMB_ASSERT ( ret = = 0 ) ;
}
2010-11-27 17:48:21 +03:00
}
/**
* Iterate through all entries which key matches to specified pattern
*
* @ param fn pointer to the function that will be supplied with each single
* matching cache entry ( key , value and timeout ) as an arguments
* @ param data void pointer to an arbitrary data that is passed directly to the fn
* function on each call
* @ param keystr_pattern pattern the existing entries ' keys are matched to
*
* */
struct gencache_iterate_state {
void ( * fn ) ( const char * key , const char * value , time_t timeout ,
void * priv ) ;
void * private_data ;
} ;
static void gencache_iterate_fn ( const char * key , DATA_BLOB value ,
time_t timeout , void * private_data )
{
struct gencache_iterate_state * state =
( struct gencache_iterate_state * ) private_data ;
char * valstr ;
char * free_val = NULL ;
if ( value . data [ value . length - 1 ] = = ' \0 ' ) {
valstr = ( char * ) value . data ;
} else {
/* ensure 0-termination */
2013-09-04 10:57:59 +04:00
valstr = talloc_strndup ( talloc_tos ( ) , ( char * ) value . data , value . length ) ;
2010-11-27 17:48:21 +03:00
free_val = valstr ;
2013-09-04 10:57:59 +04:00
if ( valstr = = NULL ) {
goto done ;
}
2010-11-27 17:48:21 +03:00
}
DEBUG ( 10 , ( " Calling function with arguments "
2013-02-11 16:42:58 +04:00
" (key=[%s], value=[%s], timeout=[%s]) \n " ,
2013-02-13 12:45:09 +04:00
key , valstr , timestring ( talloc_tos ( ) , timeout ) ) ) ;
2010-11-27 17:48:21 +03:00
state - > fn ( key , valstr , timeout , state - > private_data ) ;
2013-09-04 10:57:59 +04:00
done :
TALLOC_FREE ( free_val ) ;
2010-11-27 17:48:21 +03:00
}
void gencache_iterate ( void ( * fn ) ( const char * key , const char * value ,
time_t timeout , void * dptr ) ,
void * private_data , const char * pattern )
{
struct gencache_iterate_state state ;
if ( fn = = NULL ) {
return ;
}
state . fn = fn ;
state . private_data = private_data ;
gencache_iterate_blobs ( gencache_iterate_fn , & state , pattern ) ;
2002-09-11 18:07:21 +04:00
}