2007-10-25 01:16:54 +04:00
/*
2002-08-16 04:25:48 +04:00
Unix SMB / CIFS implementation .
2003-01-04 11:48:15 +03:00
NetBIOS name cache module on top of gencache mechanism .
2007-10-25 01:16:54 +04:00
2003-01-04 11:48:15 +03:00
Copyright ( C ) Tim Potter 2002
Copyright ( C ) Rafal Szczesniak 2002
2007-10-25 01:16:54 +04:00
Copyright ( C ) Jeremy Allison 2007
2002-08-16 04:25:48 +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-08-16 04:25:48 +04:00
( at your option ) any later version .
2007-10-25 01:16:54 +04:00
2002-08-16 04:25:48 +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 .
2007-10-25 01:16:54 +04:00
2002-08-16 04:25:48 +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-08-16 04:25:48 +04:00
*/
# include "includes.h"
2018-10-18 22:53:36 +03:00
# include "lib/gencache.h"
2020-08-27 01:42:15 +03:00
# include "libsmb/namequery.h"
2002-08-16 04:25:48 +04:00
2020-07-15 21:43:03 +03:00
# define IPSTR_LIST_SEP ","
# define IPSTR_LIST_CHAR ','
2020-08-27 21:40:10 +03:00
/**
* Allocate and initialise an ipstr list using samba_sockaddr ip adresses
* passed as arguments .
*
* @ param ctx TALLOC_CTX to use
* @ param ip_list array of ip addresses to place in the list
* @ param ip_count number of addresses stored in ip_list
* @ return pointer to allocated ip string
* */
static char * ipstr_list_make_sa ( TALLOC_CTX * ctx ,
const struct samba_sockaddr * sa_list ,
size_t ip_count )
{
char * ipstr_list = NULL ;
size_t i ;
/* arguments checking */
if ( sa_list = = NULL ) {
return NULL ;
}
/* process ip addresses given as arguments */
for ( i = 0 ; i < ip_count ; i + + ) {
char addr_buf [ INET6_ADDRSTRLEN ] ;
char * new_str = NULL ;
print_sockaddr ( addr_buf ,
sizeof ( addr_buf ) ,
& sa_list [ i ] . u . ss ) ;
if ( sa_list [ i ] . u . ss . ss_family = = AF_INET ) {
/* IPv4 - port no longer used, store 0 */
new_str = talloc_asprintf ( ctx ,
" %s:%d " ,
addr_buf ,
0 ) ;
} else {
/* IPv6 - port no longer used, store 0 */
new_str = talloc_asprintf ( ctx ,
" [%s]:%d " ,
addr_buf ,
0 ) ;
}
if ( new_str = = NULL ) {
TALLOC_FREE ( ipstr_list ) ;
return NULL ;
}
if ( ipstr_list = = NULL ) {
/* First ip address. */
ipstr_list = new_str ;
} else {
/*
* Append the separator " , " and then the new
* ip address to the existing list .
*
* The efficiency here is horrible , but
* ip_count should be small enough we can
* live with it .
*/
char * tmp = talloc_asprintf ( ctx ,
" %s%s%s " ,
ipstr_list ,
IPSTR_LIST_SEP ,
new_str ) ;
if ( tmp = = NULL ) {
TALLOC_FREE ( new_str ) ;
TALLOC_FREE ( ipstr_list ) ;
return NULL ;
}
TALLOC_FREE ( new_str ) ;
TALLOC_FREE ( ipstr_list ) ;
ipstr_list = tmp ;
}
}
return ipstr_list ;
}
2020-07-15 21:43:03 +03:00
/**
* Parse given ip string list into array of ip addresses
* ( as ip_service structures )
* e . g . [ IPv6 ] : port , 192.168 .1 .100 : 389 , 192.168 .1 .78 , . . .
*
* @ param ipstr ip string list to be parsed
* @ param ip_list pointer to array of ip addresses which is
2020-08-27 01:42:15 +03:00
* talloced by this function and must be freed by caller
2020-07-15 21:43:03 +03:00
* @ return number of successfully parsed addresses
* */
2020-08-27 01:42:15 +03:00
static int ipstr_list_parse ( TALLOC_CTX * ctx ,
const char * ipstr_list ,
struct samba_sockaddr * * sa_list_out )
2020-07-15 21:43:03 +03:00
{
2020-08-27 01:42:15 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct samba_sockaddr * sa_list = NULL ;
2020-07-15 21:43:03 +03:00
char * token_str = NULL ;
size_t i , count ;
2020-08-27 01:42:15 +03:00
size_t array_size ;
2020-07-15 21:43:03 +03:00
2020-08-27 01:42:15 +03:00
* sa_list_out = NULL ;
2020-07-15 21:43:03 +03:00
2020-08-27 01:42:15 +03:00
array_size = count_chars ( ipstr_list , IPSTR_LIST_CHAR ) + 1 ;
sa_list = talloc_zero_array ( frame ,
struct samba_sockaddr ,
array_size ) ;
if ( sa_list = = NULL ) {
TALLOC_FREE ( frame ) ;
2020-07-15 21:43:03 +03:00
return 0 ;
}
2020-08-27 01:42:15 +03:00
count = 0 ;
for ( i = 0 ; next_token_talloc ( frame , & ipstr_list , & token_str ,
IPSTR_LIST_SEP ) ; i + + ) {
bool ok ;
2020-07-15 21:43:03 +03:00
char * s = token_str ;
char * p = strrchr ( token_str , ' : ' ) ;
2020-08-27 01:42:15 +03:00
struct sockaddr_storage ss ;
/* Ensure we don't overrun. */
if ( count > = array_size ) {
break ;
}
2020-07-15 21:43:03 +03:00
if ( p ) {
* p = 0 ;
2020-08-27 01:42:15 +03:00
/* We now ignore the port. */
2020-07-15 21:43:03 +03:00
}
/* convert single token to ip address */
if ( token_str [ 0 ] = = ' [ ' ) {
/* IPv6 address. */
s + + ;
p = strchr ( token_str , ' ] ' ) ;
if ( ! p ) {
continue ;
}
* p = ' \0 ' ;
}
2020-08-27 01:42:15 +03:00
ok = interpret_string_addr ( & ss , s , AI_NUMERICHOST ) ;
if ( ! ok ) {
continue ;
}
ok = sockaddr_storage_to_samba_sockaddr ( & sa_list [ count ] ,
& ss ) ;
if ( ! ok ) {
2020-07-15 21:43:03 +03:00
continue ;
}
2020-08-27 01:42:15 +03:00
count + + ;
}
if ( count > 0 ) {
* sa_list_out = talloc_move ( ctx , & sa_list ) ;
2020-07-15 21:43:03 +03:00
}
TALLOC_FREE ( frame ) ;
return count ;
}
2003-01-04 11:48:15 +03:00
# define NBTKEY_FMT "NBT / %s#%02X"
2002-08-16 04:25:48 +04:00
2003-01-04 11:48:15 +03:00
/**
* Generates a key for netbios name lookups on basis of
* netbios name and type .
* The caller must free returned key string when finished .
*
* @ param name netbios name string ( case insensitive )
* @ param name_type netbios type of the name being looked up
*
* @ return string consisted of uppercased name and appended
* type number
*/
2002-08-16 04:25:48 +04:00
2020-07-15 23:37:59 +03:00
static char * namecache_key ( TALLOC_CTX * ctx ,
const char * name ,
int name_type )
2003-01-04 11:48:15 +03:00
{
2020-07-15 23:37:59 +03:00
return talloc_asprintf_strupper_m ( ctx ,
NBTKEY_FMT ,
name ,
name_type ) ;
2002-08-16 04:25:48 +04:00
}
2020-08-27 21:45:17 +03:00
/**
* Store a name ( s ) in the name cache - samba_sockaddr version .
*
* @ param name netbios names array
* @ param name_type integer netbios name type
* @ param num_names number of names being stored
* @ param ip_list array of in_addr structures containing
* ip addresses being stored
* */
2020-08-27 22:17:07 +03:00
bool namecache_store ( const char * name ,
2020-08-27 21:45:17 +03:00
int name_type ,
size_t num_names ,
struct samba_sockaddr * sa_list )
{
time_t expiry ;
char * key = NULL ;
char * value_string = NULL ;
size_t i ;
bool ret = false ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( name_type > 255 ) {
/* Don't store non-real name types. */
goto out ;
}
if ( DEBUGLEVEL > = 5 ) {
char * addr = NULL ;
DBG_INFO ( " storing %zu address%s for %s#%02x: " ,
num_names , num_names = = 1 ? " " : " es " , name , name_type ) ;
for ( i = 0 ; i < num_names ; i + + ) {
addr = print_canonical_sockaddr ( frame ,
& sa_list [ i ] . u . ss ) ;
if ( ! addr ) {
continue ;
}
DEBUGADD ( 5 , ( " %s%s " , addr ,
( i = = ( num_names - 1 ) ? " " : " , " ) ) ) ;
}
DEBUGADD ( 5 , ( " \n " ) ) ;
}
key = namecache_key ( frame , name , name_type ) ;
if ( ! key ) {
goto out ;
}
expiry = time ( NULL ) + lp_name_cache_timeout ( ) ;
/*
* Generate string representation of ip addresses list
*/
value_string = ipstr_list_make_sa ( frame , sa_list , num_names ) ;
if ( value_string = = NULL ) {
goto out ;
}
/* set the entry */
ret = gencache_set ( key , value_string , expiry ) ;
2020-07-15 23:33:27 +03:00
out :
2020-07-15 23:37:59 +03:00
TALLOC_FREE ( key ) ;
2020-07-16 01:02:02 +03:00
TALLOC_FREE ( value_string ) ;
2020-07-15 23:28:33 +03:00
TALLOC_FREE ( frame ) ;
2003-03-23 02:32:50 +03:00
return ret ;
2002-08-16 04:25:48 +04:00
}
2003-01-04 11:48:15 +03:00
/**
* Look up a name in the cache .
*
* @ param name netbios name to look up for
* @ param name_type netbios name type of @ param name
2020-08-27 01:42:15 +03:00
* @ param ip_list talloced list of IP addresses if found in the cache ,
2003-01-04 11:48:15 +03:00
* NULL otherwise
* @ param num_names number of entries found
*
* @ return true upon successful fetch or
* false if name isn ' t found in the cache or has expired
* */
2002-08-16 04:25:48 +04:00
2020-08-27 01:42:15 +03:00
bool namecache_fetch ( TALLOC_CTX * ctx ,
const char * name ,
int name_type ,
struct samba_sockaddr * * sa_list ,
size_t * num_names )
2002-08-16 04:25:48 +04:00
{
2003-01-04 11:48:15 +03:00
char * key , * value ;
2008-07-11 19:44:25 +04:00
time_t timeout ;
2002-08-16 04:25:48 +04:00
2006-09-02 23:27:44 +04:00
if ( name_type > 255 ) {
2020-07-15 22:12:23 +03:00
return false ; /* Don't fetch non-real name types. */
2006-09-02 23:27:44 +04:00
}
2006-08-28 09:10:56 +04:00
* num_names = 0 ;
2007-10-25 01:16:54 +04:00
/*
2003-01-04 11:48:15 +03:00
* Use gencache interface - lookup the key
*/
2020-07-15 23:37:59 +03:00
key = namecache_key ( talloc_tos ( ) , name , name_type ) ;
2006-10-11 22:54:40 +04:00
if ( ! key ) {
2020-07-15 22:12:23 +03:00
return false ;
2006-10-11 22:54:40 +04:00
}
2002-08-16 04:25:48 +04:00
2013-09-04 10:57:59 +04:00
if ( ! gencache_get ( key , talloc_tos ( ) , & value , & timeout ) ) {
2020-07-16 00:41:45 +03:00
DBG_INFO ( " no entry for %s#%02X found. \n " , name , name_type ) ;
2020-07-15 23:37:59 +03:00
TALLOC_FREE ( key ) ;
2020-07-15 22:12:23 +03:00
return false ;
2002-09-25 19:19:00 +04:00
}
2007-10-25 01:16:54 +04:00
2020-07-16 00:41:45 +03:00
DBG_INFO ( " name %s#%02X found. \n " , name , name_type ) ;
2011-01-12 12:26:49 +03:00
2003-01-04 11:48:15 +03:00
/*
* Split up the stored value into the list of IP adresses
*/
2020-08-27 01:42:15 +03:00
* num_names = ipstr_list_parse ( ctx , value , sa_list ) ;
2007-10-25 01:16:54 +04:00
2020-07-15 23:37:59 +03:00
TALLOC_FREE ( key ) ;
2013-09-04 10:57:59 +04:00
TALLOC_FREE ( value ) ;
2007-10-25 01:16:54 +04:00
return * num_names > 0 ; /* true only if some ip has been fetched */
2003-01-04 11:48:15 +03:00
}
2002-08-16 04:25:48 +04:00
2006-10-11 22:54:40 +04:00
/**
* Remove a namecache entry . Needed for site support .
*
* */
2007-10-19 04:40:25 +04:00
bool namecache_delete ( const char * name , int name_type )
2006-10-11 22:54:40 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret ;
2006-10-11 22:54:40 +04:00
char * key ;
if ( name_type > 255 ) {
2020-07-15 22:12:23 +03:00
return false ; /* Don't fetch non-real name types. */
2006-10-11 22:54:40 +04:00
}
2020-07-15 23:37:59 +03:00
key = namecache_key ( talloc_tos ( ) , name , name_type ) ;
2006-10-11 22:54:40 +04:00
if ( ! key ) {
2020-07-15 22:12:23 +03:00
return false ;
2006-10-11 22:54:40 +04:00
}
ret = gencache_del ( key ) ;
2020-07-15 23:37:59 +03:00
TALLOC_FREE ( key ) ;
2006-10-11 22:54:40 +04:00
return ret ;
}
2002-08-16 04:25:48 +04:00
2003-01-04 11:48:15 +03:00
/**
* Delete single namecache entry . Look at the
* gencache_iterate definition .
*
* */
2002-08-16 04:25:48 +04:00
2007-10-25 01:16:54 +04:00
static void flush_netbios_name ( const char * key ,
const char * value ,
time_t timeout ,
void * dptr )
2003-01-04 11:48:15 +03:00
{
gencache_del ( key ) ;
2020-07-16 00:41:45 +03:00
DBG_INFO ( " Deleting entry %s \n " , key ) ;
2002-08-16 04:25:48 +04:00
}
2003-01-04 11:48:15 +03:00
/**
* Flush all names from the name cache .
* It ' s done by gencache_iterate ( )
*
2007-10-25 01:16:54 +04:00
* @ return true upon successful deletion or
* false in case of an error
2003-01-04 11:48:15 +03:00
* */
2002-08-16 04:25:48 +04:00
void namecache_flush ( void )
{
2007-10-25 01:16:54 +04:00
/*
2003-01-04 11:48:15 +03:00
* iterate through each NBT cache ' s entry and flush it
* by flush_netbios_name function
*/
gencache_iterate ( flush_netbios_name , NULL , " NBT/* " ) ;
2020-07-16 00:41:45 +03:00
DBG_INFO ( " Namecache flushed \n " ) ;
2002-08-16 04:25:48 +04:00
}
2003-01-04 11:48:15 +03:00
2003-06-14 01:03:15 +04:00
/* Construct a name status record key. */
2020-07-16 00:38:23 +03:00
static char * namecache_status_record_key ( TALLOC_CTX * ctx ,
const char * name ,
2007-10-25 01:16:54 +04:00
int name_type1 ,
int name_type2 ,
const struct sockaddr_storage * keyip )
2003-06-14 01:03:15 +04:00
{
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2003-06-14 01:03:15 +04:00
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , keyip ) ;
2020-07-16 00:38:23 +03:00
return talloc_asprintf_strupper_m ( ctx ,
" NBT/%s#%02X.%02X.%s " ,
name ,
name_type1 ,
name_type2 ,
addr ) ;
2003-06-14 01:03:15 +04:00
}
/* Store a name status record. */
2007-10-19 04:40:25 +04:00
bool namecache_status_store ( const char * keyname , int keyname_type ,
2007-10-25 01:16:54 +04:00
int name_type , const struct sockaddr_storage * keyip ,
2003-06-14 01:03:15 +04:00
const char * srvname )
{
char * key ;
time_t expiry ;
2007-10-19 04:40:25 +04:00
bool ret ;
2003-06-14 01:03:15 +04:00
2020-07-16 00:38:23 +03:00
key = namecache_status_record_key ( talloc_tos ( ) ,
keyname ,
keyname_type ,
name_type ,
keyip ) ;
2003-06-14 01:03:15 +04:00
if ( ! key )
2020-07-15 22:12:23 +03:00
return false ;
2003-06-14 01:03:15 +04:00
expiry = time ( NULL ) + lp_name_cache_timeout ( ) ;
ret = gencache_set ( key , srvname , expiry ) ;
2007-10-25 01:16:54 +04:00
if ( ret ) {
2020-07-16 00:41:45 +03:00
DBG_INFO ( " entry %s -> %s \n " , key , srvname ) ;
2007-10-25 01:16:54 +04:00
} else {
2020-07-16 00:41:45 +03:00
DBG_INFO ( " entry %s store failed. \n " , key ) ;
2007-10-25 01:16:54 +04:00
}
2003-06-14 01:03:15 +04:00
2020-07-16 00:38:23 +03:00
TALLOC_FREE ( key ) ;
2003-06-14 01:03:15 +04:00
return ret ;
}
/* Fetch a name status record. */
2007-10-25 01:16:54 +04:00
bool namecache_status_fetch ( const char * keyname ,
int keyname_type ,
int name_type ,
const struct sockaddr_storage * keyip ,
char * srvname_out )
2003-06-14 01:03:15 +04:00
{
char * key = NULL ;
char * value = NULL ;
2008-07-11 19:44:25 +04:00
time_t timeout ;
2003-06-14 01:03:15 +04:00
2020-07-16 00:38:23 +03:00
key = namecache_status_record_key ( talloc_tos ( ) ,
keyname ,
keyname_type ,
name_type ,
keyip ) ;
2003-06-14 01:03:15 +04:00
if ( ! key )
2020-07-15 22:12:23 +03:00
return false ;
2003-06-14 01:03:15 +04:00
2013-09-04 10:57:59 +04:00
if ( ! gencache_get ( key , talloc_tos ( ) , & value , & timeout ) ) {
2020-07-16 00:41:45 +03:00
DBG_INFO ( " no entry for %s found. \n " , key ) ;
2020-07-16 00:38:23 +03:00
TALLOC_FREE ( key ) ;
2020-07-15 22:12:23 +03:00
return false ;
2003-06-14 01:03:15 +04:00
} else {
2020-07-16 00:41:45 +03:00
DBG_INFO ( " key %s -> %s \n " , key , value ) ;
2003-06-14 01:03:15 +04:00
}
strlcpy ( srvname_out , value , 16 ) ;
2020-07-16 00:38:23 +03:00
TALLOC_FREE ( key ) ;
2013-09-04 10:57:59 +04:00
TALLOC_FREE ( value ) ;
2020-07-15 22:12:23 +03:00
return true ;
2003-06-14 01:03:15 +04:00
}