2007-10-24 14:16:54 -07:00
/*
2002-08-16 00:25:48 +00:00
Unix SMB / CIFS implementation .
2003-01-04 08:48:15 +00:00
NetBIOS name cache module on top of gencache mechanism .
2007-10-24 14:16:54 -07:00
2003-01-04 08:48:15 +00:00
Copyright ( C ) Tim Potter 2002
Copyright ( C ) Rafal Szczesniak 2002
2007-10-24 14:16:54 -07:00
Copyright ( C ) Jeremy Allison 2007
2002-08-16 00:25:48 +00: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 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2002-08-16 00:25:48 +00:00
( at your option ) any later version .
2007-10-24 14:16:54 -07:00
2002-08-16 00:25:48 +00: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-24 14:16:54 -07:00
2002-08-16 00:25:48 +00:00
You should have received a copy of the GNU General Public License
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-08-16 00:25:48 +00:00
*/
# include "includes.h"
2018-10-18 21:53:36 +02:00
# include "lib/gencache.h"
2002-08-16 00:25:48 +00:00
2020-07-15 11:43:03 -07:00
# define IPSTR_LIST_SEP ","
# define IPSTR_LIST_CHAR ','
/**
* Add ip string representation to ipstr list . Used also
* as part of @ function ipstr_list_make
*
* @ param ipstr_list pointer to string containing ip list ;
* MUST BE already allocated and IS reallocated if necessary
* @ param ipstr_size pointer to current size of ipstr_list ( might be changed
* as a result of reallocation )
* @ param ip IP address which is to be added to list
* @ return pointer to string appended with new ip and possibly
* reallocated to new length
* */
static char * ipstr_list_add ( char * * ipstr_list , const struct ip_service * service )
{
char * new_ipstr = NULL ;
char addr_buf [ INET6_ADDRSTRLEN ] ;
int ret ;
/* arguments checking */
if ( ! ipstr_list | | ! service ) {
return NULL ;
}
print_sockaddr ( addr_buf ,
sizeof ( addr_buf ) ,
& service - > ss ) ;
/* attempt to convert ip to a string and append colon separator to it */
if ( * ipstr_list ) {
if ( service - > ss . ss_family = = AF_INET ) {
/* IPv4 */
ret = asprintf ( & new_ipstr , " %s%s%s:%d " , * ipstr_list ,
IPSTR_LIST_SEP , addr_buf ,
service - > port ) ;
} else {
/* IPv6 */
ret = asprintf ( & new_ipstr , " %s%s[%s]:%d " , * ipstr_list ,
IPSTR_LIST_SEP , addr_buf ,
service - > port ) ;
}
SAFE_FREE ( * ipstr_list ) ;
} else {
if ( service - > ss . ss_family = = AF_INET ) {
/* IPv4 */
ret = asprintf ( & new_ipstr , " %s:%d " , addr_buf ,
service - > port ) ;
} else {
/* IPv6 */
ret = asprintf ( & new_ipstr , " [%s]:%d " , addr_buf ,
service - > port ) ;
}
}
if ( ret = = - 1 ) {
return NULL ;
}
* ipstr_list = new_ipstr ;
return * ipstr_list ;
}
/**
* Allocate and initialise an ipstr list using ip adresses
* passed as arguments .
*
* @ param ipstr_list pointer to string meant to be allocated and set
* @ 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
* */
2020-07-15 11:58:45 -07:00
static char * ipstr_list_make ( char * * ipstr_list ,
2020-07-15 11:43:03 -07:00
const struct ip_service * ip_list ,
int ip_count )
{
int i ;
/* arguments checking */
if ( ! ip_list | | ! ipstr_list ) {
return 0 ;
}
* ipstr_list = NULL ;
/* process ip addresses given as arguments */
for ( i = 0 ; i < ip_count ; i + + ) {
* ipstr_list = ipstr_list_add ( ipstr_list , & ip_list [ i ] ) ;
}
return ( * ipstr_list ) ;
}
/**
* 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
* allocated by this function and must be freed by caller
* @ return number of successfully parsed addresses
* */
2020-07-15 11:58:45 -07:00
static int ipstr_list_parse ( const char * ipstr_list , struct ip_service * * ip_list )
2020-07-15 11:43:03 -07:00
{
TALLOC_CTX * frame ;
char * token_str = NULL ;
size_t i , count ;
if ( ! ipstr_list | | ! ip_list )
return 0 ;
count = count_chars ( ipstr_list , IPSTR_LIST_CHAR ) + 1 ;
if ( ( * ip_list = SMB_MALLOC_ARRAY ( struct ip_service , count ) ) = = NULL ) {
DEBUG ( 0 , ( " ipstr_list_parse: malloc failed for %lu entries \n " ,
( unsigned long ) count ) ) ;
return 0 ;
}
frame = talloc_stackframe ( ) ;
for ( i = 0 ; next_token_talloc ( frame , & ipstr_list , & token_str ,
IPSTR_LIST_SEP ) & & i < count ; i + + ) {
char * s = token_str ;
char * p = strrchr ( token_str , ' : ' ) ;
if ( p ) {
* p = 0 ;
( * ip_list ) [ i ] . port = atoi ( p + 1 ) ;
}
/* convert single token to ip address */
if ( token_str [ 0 ] = = ' [ ' ) {
/* IPv6 address. */
s + + ;
p = strchr ( token_str , ' ] ' ) ;
if ( ! p ) {
continue ;
}
* p = ' \0 ' ;
}
if ( ! interpret_string_addr ( & ( * ip_list ) [ i ] . ss ,
s ,
AI_NUMERICHOST ) ) {
continue ;
}
}
TALLOC_FREE ( frame ) ;
return count ;
}
2003-01-04 08:48:15 +00:00
# define NBTKEY_FMT "NBT / %s#%02X"
2002-08-16 00:25:48 +00:00
2003-01-04 08:48:15 +00: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 00:25:48 +00:00
2014-09-12 13:11:00 +02:00
static char * namecache_key ( const char * name ,
2007-10-24 14:16:54 -07:00
int name_type )
2003-01-04 08:48:15 +00:00
{
2014-09-12 13:11:00 +02:00
char * keystr = NULL ;
2007-11-24 17:27:54 +01:00
asprintf_strupper_m ( & keystr , NBTKEY_FMT , name , name_type ) ;
2002-08-16 00:25:48 +00:00
2003-01-04 08:48:15 +00:00
return keystr ;
2002-08-16 00:25:48 +00:00
}
2003-01-04 08:48:15 +00:00
/**
* Store a name ( s ) in the name cache
*
* @ 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
* */
2007-10-24 14:16:54 -07:00
bool namecache_store ( const char * name ,
int name_type ,
int num_names ,
struct ip_service * ip_list )
2002-08-16 00:25:48 +00:00
{
time_t expiry ;
2003-01-04 08:48:15 +00:00
char * key , * value_string ;
2002-08-16 00:25:48 +00:00
int i ;
2007-10-18 17:40:25 -07:00
bool ret ;
2020-07-15 13:28:33 -07:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2002-08-16 00:25:48 +00:00
2006-09-02 19:27:44 +00:00
if ( name_type > 255 ) {
2020-07-15 13:28:33 -07:00
TALLOC_FREE ( frame ) ;
2020-07-15 12:12:23 -07:00
return false ; /* Don't store non-real name types. */
2006-09-02 19:27:44 +00:00
}
2003-06-25 17:41:05 +00:00
if ( DEBUGLEVEL > = 5 ) {
2007-10-24 14:16:54 -07:00
char * addr = NULL ;
2003-06-25 17:41:05 +00:00
DEBUG ( 5 , ( " namecache_store: storing %d address%s for %s#%02x: " ,
num_names , num_names = = 1 ? " " : " es " , name , name_type ) ) ;
2002-08-16 00:25:48 +00:00
2007-10-24 14:16:54 -07:00
for ( i = 0 ; i < num_names ; i + + ) {
2020-07-15 13:28:33 -07:00
addr = print_canonical_sockaddr ( frame ,
2007-10-24 14:16:54 -07:00
& ip_list [ i ] . ss ) ;
if ( ! addr ) {
continue ;
}
DEBUGADD ( 5 , ( " %s%s " , addr ,
( i = = ( num_names - 1 ) ? " " : " , " ) ) ) ;
}
2003-06-25 17:41:05 +00:00
DEBUGADD ( 5 , ( " \n " ) ) ;
}
2007-10-24 14:16:54 -07:00
2002-08-16 00:25:48 +00:00
key = namecache_key ( name , name_type ) ;
2006-10-11 18:54:40 +00:00
if ( ! key ) {
2020-07-15 13:28:33 -07:00
TALLOC_FREE ( frame ) ;
2020-07-15 12:12:23 -07:00
return false ;
2006-10-11 18:54:40 +00:00
}
2003-06-13 21:03:15 +00:00
expiry = time ( NULL ) + lp_name_cache_timeout ( ) ;
2002-08-16 00:25:48 +00:00
2003-01-04 08:48:15 +00:00
/*
* Generate string representation of ip addresses list
* First , store the number of ip addresses and then
* place each single ip
*/
2003-03-22 23:32:50 +00:00
if ( ! ipstr_list_make ( & value_string , ip_list , num_names ) ) {
SAFE_FREE ( key ) ;
SAFE_FREE ( value_string ) ;
2020-07-15 13:28:33 -07:00
TALLOC_FREE ( frame ) ;
2007-10-24 14:16:54 -07:00
return false ;
2003-03-22 23:32:50 +00:00
}
2007-10-24 14:16:54 -07:00
2003-01-04 08:48:15 +00:00
/* set the entry */
2003-03-22 23:32:50 +00:00
ret = gencache_set ( key , value_string , expiry ) ;
SAFE_FREE ( key ) ;
SAFE_FREE ( value_string ) ;
2020-07-15 13:28:33 -07:00
TALLOC_FREE ( frame ) ;
2003-03-22 23:32:50 +00:00
return ret ;
2002-08-16 00:25:48 +00:00
}
2003-01-04 08:48:15 +00: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
* @ param ip_list mallocated list of IP addresses if found in the cache ,
* 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 00:25:48 +00:00
2007-10-24 14:16:54 -07:00
bool namecache_fetch ( const char * name ,
int name_type ,
struct ip_service * * ip_list ,
int * num_names )
2002-08-16 00:25:48 +00:00
{
2003-01-04 08:48:15 +00:00
char * key , * value ;
2008-07-11 17:44:25 +02:00
time_t timeout ;
2002-08-16 00:25:48 +00:00
2003-01-04 08:48:15 +00:00
/* exit now if null pointers were passed as they're required further */
2007-10-24 14:16:54 -07:00
if ( ! ip_list | | ! num_names ) {
2020-07-15 12:12:23 -07:00
return false ;
2007-10-24 14:16:54 -07:00
}
2002-08-16 00:25:48 +00:00
2006-09-02 19:27:44 +00:00
if ( name_type > 255 ) {
2020-07-15 12:12:23 -07:00
return false ; /* Don't fetch non-real name types. */
2006-09-02 19:27:44 +00:00
}
2006-08-28 05:10:56 +00:00
* num_names = 0 ;
2007-10-24 14:16:54 -07:00
/*
2003-01-04 08:48:15 +00:00
* Use gencache interface - lookup the key
*/
2002-08-16 00:25:48 +00:00
key = namecache_key ( name , name_type ) ;
2006-10-11 18:54:40 +00:00
if ( ! key ) {
2020-07-15 12:12:23 -07:00
return false ;
2006-10-11 18:54:40 +00:00
}
2002-08-16 00:25:48 +00:00
2013-09-04 08:57:59 +02:00
if ( ! gencache_get ( key , talloc_tos ( ) , & value , & timeout ) ) {
2003-01-04 08:48:15 +00:00
DEBUG ( 5 , ( " no entry for %s#%02X found. \n " , name , name_type ) ) ;
SAFE_FREE ( key ) ;
2020-07-15 12:12:23 -07:00
return false ;
2002-09-25 15:19:00 +00:00
}
2007-10-24 14:16:54 -07:00
2011-01-12 10:26:49 +01:00
DEBUG ( 5 , ( " name %s#%02X found. \n " , name , name_type ) ) ;
2003-01-04 08:48:15 +00:00
/*
* Split up the stored value into the list of IP adresses
*/
* num_names = ipstr_list_parse ( value , ip_list ) ;
2007-10-24 14:16:54 -07:00
2003-01-04 08:48:15 +00:00
SAFE_FREE ( key ) ;
2013-09-04 08:57:59 +02:00
TALLOC_FREE ( value ) ;
2007-10-24 14:16:54 -07:00
return * num_names > 0 ; /* true only if some ip has been fetched */
2003-01-04 08:48:15 +00:00
}
2002-08-16 00:25:48 +00:00
2006-10-11 18:54:40 +00:00
/**
* Remove a namecache entry . Needed for site support .
*
* */
2007-10-18 17:40:25 -07:00
bool namecache_delete ( const char * name , int name_type )
2006-10-11 18:54:40 +00:00
{
2007-10-18 17:40:25 -07:00
bool ret ;
2006-10-11 18:54:40 +00:00
char * key ;
if ( name_type > 255 ) {
2020-07-15 12:12:23 -07:00
return false ; /* Don't fetch non-real name types. */
2006-10-11 18:54:40 +00:00
}
key = namecache_key ( name , name_type ) ;
if ( ! key ) {
2020-07-15 12:12:23 -07:00
return false ;
2006-10-11 18:54:40 +00:00
}
ret = gencache_del ( key ) ;
SAFE_FREE ( key ) ;
return ret ;
}
2002-08-16 00:25:48 +00:00
2003-01-04 08:48:15 +00:00
/**
* Delete single namecache entry . Look at the
* gencache_iterate definition .
*
* */
2002-08-16 00:25:48 +00:00
2007-10-24 14:16:54 -07:00
static void flush_netbios_name ( const char * key ,
const char * value ,
time_t timeout ,
void * dptr )
2003-01-04 08:48:15 +00:00
{
gencache_del ( key ) ;
DEBUG ( 5 , ( " Deleting entry %s \n " , key ) ) ;
2002-08-16 00:25:48 +00:00
}
2003-01-04 08:48:15 +00:00
/**
* Flush all names from the name cache .
* It ' s done by gencache_iterate ( )
*
2007-10-24 14:16:54 -07:00
* @ return true upon successful deletion or
* false in case of an error
2003-01-04 08:48:15 +00:00
* */
2002-08-16 00:25:48 +00:00
void namecache_flush ( void )
{
2007-10-24 14:16:54 -07:00
/*
2003-01-04 08:48:15 +00:00
* iterate through each NBT cache ' s entry and flush it
* by flush_netbios_name function
*/
gencache_iterate ( flush_netbios_name , NULL , " NBT/* " ) ;
DEBUG ( 5 , ( " Namecache flushed \n " ) ) ;
2002-08-16 00:25:48 +00:00
}
2003-01-04 08:48:15 +00:00
2003-06-13 21:03:15 +00:00
/* Construct a name status record key. */
2007-10-24 14:16:54 -07:00
static char * namecache_status_record_key ( const char * name ,
int name_type1 ,
int name_type2 ,
const struct sockaddr_storage * keyip )
2003-06-13 21:03:15 +00:00
{
2007-10-24 14:16:54 -07:00
char addr [ INET6_ADDRSTRLEN ] ;
2014-09-12 13:11:00 +02:00
char * keystr = NULL ;
2003-06-13 21:03:15 +00:00
2007-10-24 14:16:54 -07:00
print_sockaddr ( addr , sizeof ( addr ) , keyip ) ;
2007-11-24 17:27:54 +01:00
asprintf_strupper_m ( & keystr , " NBT/%s#%02X.%02X.%s " , name ,
name_type1 , name_type2 , addr ) ;
2003-06-13 21:03:15 +00:00
return keystr ;
}
/* Store a name status record. */
2007-10-18 17:40:25 -07:00
bool namecache_status_store ( const char * keyname , int keyname_type ,
2007-10-24 14:16:54 -07:00
int name_type , const struct sockaddr_storage * keyip ,
2003-06-13 21:03:15 +00:00
const char * srvname )
{
char * key ;
time_t expiry ;
2007-10-18 17:40:25 -07:00
bool ret ;
2003-06-13 21:03:15 +00:00
2007-10-24 14:16:54 -07:00
key = namecache_status_record_key ( keyname , keyname_type ,
name_type , keyip ) ;
2003-06-13 21:03:15 +00:00
if ( ! key )
2020-07-15 12:12:23 -07:00
return false ;
2003-06-13 21:03:15 +00:00
expiry = time ( NULL ) + lp_name_cache_timeout ( ) ;
ret = gencache_set ( key , srvname , expiry ) ;
2007-10-24 14:16:54 -07:00
if ( ret ) {
DEBUG ( 5 , ( " namecache_status_store: entry %s -> %s \n " ,
key , srvname ) ) ;
} else {
DEBUG ( 5 , ( " namecache_status_store: entry %s store failed. \n " ,
key ) ) ;
}
2003-06-13 21:03:15 +00:00
SAFE_FREE ( key ) ;
return ret ;
}
/* Fetch a name status record. */
2007-10-24 14:16:54 -07:00
bool namecache_status_fetch ( const char * keyname ,
int keyname_type ,
int name_type ,
const struct sockaddr_storage * keyip ,
char * srvname_out )
2003-06-13 21:03:15 +00:00
{
char * key = NULL ;
char * value = NULL ;
2008-07-11 17:44:25 +02:00
time_t timeout ;
2003-06-13 21:03:15 +00:00
2007-10-24 14:16:54 -07:00
key = namecache_status_record_key ( keyname , keyname_type ,
name_type , keyip ) ;
2003-06-13 21:03:15 +00:00
if ( ! key )
2020-07-15 12:12:23 -07:00
return false ;
2003-06-13 21:03:15 +00:00
2013-09-04 08:57:59 +02:00
if ( ! gencache_get ( key , talloc_tos ( ) , & value , & timeout ) ) {
2007-10-24 14:16:54 -07:00
DEBUG ( 5 , ( " namecache_status_fetch: no entry for %s found. \n " ,
key ) ) ;
2003-06-13 21:03:15 +00:00
SAFE_FREE ( key ) ;
2020-07-15 12:12:23 -07:00
return false ;
2003-06-13 21:03:15 +00:00
} else {
2007-10-24 14:16:54 -07:00
DEBUG ( 5 , ( " namecache_status_fetch: key %s -> %s \n " ,
key , value ) ) ;
2003-06-13 21:03:15 +00:00
}
strlcpy ( srvname_out , value , 16 ) ;
SAFE_FREE ( key ) ;
2013-09-04 08:57:59 +02:00
TALLOC_FREE ( value ) ;
2020-07-15 12:12:23 -07:00
return true ;
2003-06-13 21:03:15 +00:00
}