2014-10-15 20:14:42 +04:00
/*
* Map names to server_ids
*
* Copyright Volker Lendecke < vl @ samba . org > 2014
*
* 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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "system/filesys.h"
2017-01-01 23:00:55 +03:00
# include "lib/util/server_id.h"
2014-10-15 20:14:42 +04:00
# include "lib/util/server_id_db.h"
# include "lib/tdb_wrap/tdb_wrap.h"
# include "lib/util/strv.h"
# include "lib/util/util_tdb.h"
# include "lib/util/samba_util.h"
static TDB_DATA talloc_tdb_data ( void * ptr )
{
return ( TDB_DATA ) { . dptr = ptr , . dsize = talloc_get_size ( ptr ) } ;
}
struct server_id_db {
struct server_id pid ;
struct tdb_wrap * tdb ;
char * names ;
} ;
static int server_id_db_destructor ( struct server_id_db * db ) ;
struct server_id_db * server_id_db_init ( TALLOC_CTX * mem_ctx ,
struct server_id pid ,
const char * base_path ,
int hash_size , int tdb_flags )
{
struct server_id_db * db ;
size_t pathlen = strlen ( base_path ) + 11 ;
char path [ pathlen ] ;
db = talloc ( mem_ctx , struct server_id_db ) ;
if ( db = = NULL ) {
return NULL ;
}
db - > pid = pid ;
db - > names = NULL ;
snprintf ( path , pathlen , " %s/names.tdb " , base_path ) ;
db - > tdb = tdb_wrap_open ( db , path , hash_size , tdb_flags ,
O_RDWR | O_CREAT , 0660 ) ;
if ( db - > tdb = = NULL ) {
TALLOC_FREE ( db ) ;
return NULL ;
}
talloc_set_destructor ( db , server_id_db_destructor ) ;
return db ;
}
void server_id_db_reinit ( struct server_id_db * db , struct server_id pid )
{
db - > pid = pid ;
TALLOC_FREE ( db - > names ) ;
}
2015-06-08 23:46:54 +03:00
struct server_id server_id_db_pid ( struct server_id_db * db )
{
return db - > pid ;
}
2014-10-15 20:14:42 +04:00
static int server_id_db_destructor ( struct server_id_db * db )
{
char * name = NULL ;
while ( ( name = strv_next ( db - > names , name ) ) ! = NULL ) {
server_id_db_remove ( db , name ) ;
}
return 0 ;
}
int server_id_db_add ( struct server_id_db * db , const char * name )
{
struct tdb_context * tdb = db - > tdb - > tdb ;
2015-09-29 21:24:10 +03:00
TDB_DATA key ;
2014-10-15 20:14:42 +04:00
char * n ;
int ret ;
n = strv_find ( db - > names , name ) ;
if ( n ! = NULL ) {
return EEXIST ;
}
ret = strv_add ( db , & db - > names , name ) ;
if ( ret ! = 0 ) {
return ret ;
}
key = string_term_tdb_data ( name ) ;
2015-09-29 21:24:10 +03:00
{
size_t idlen = server_id_str_buf_unique ( db - > pid , NULL , 0 ) ;
char idbuf [ idlen ] ;
server_id_str_buf_unique ( db - > pid , idbuf , idlen ) ;
ret = tdb_append (
tdb , key ,
( TDB_DATA ) { . dptr = ( uint8_t * ) idbuf , . dsize = idlen } ) ;
}
2014-10-15 20:14:42 +04:00
if ( ret ! = 0 ) {
enum TDB_ERROR err = tdb_error ( tdb ) ;
strv_delete ( & db - > names , strv_find ( db - > names , name ) ) ;
return map_unix_error_from_tdb ( err ) ;
}
return 0 ;
}
2015-04-26 12:02:27 +03:00
int server_id_db_prune_name ( struct server_id_db * db , const char * name ,
struct server_id server )
2014-10-15 20:14:42 +04:00
{
struct tdb_context * tdb = db - > tdb - > tdb ;
2015-09-29 21:24:10 +03:00
size_t idbuf_len = server_id_str_buf_unique ( server , NULL , 0 ) ;
char idbuf [ idbuf_len ] ;
2014-10-15 20:14:42 +04:00
TDB_DATA key ;
uint8_t * data ;
2017-03-23 17:48:25 +03:00
size_t datalen ;
2015-04-26 12:02:27 +03:00
char * ids , * id ;
2014-10-15 20:14:42 +04:00
int ret ;
key = string_term_tdb_data ( name ) ;
2015-09-29 21:24:10 +03:00
server_id_str_buf_unique ( server , idbuf , idbuf_len ) ;
2014-10-15 20:14:42 +04:00
ret = tdb_chainlock ( tdb , key ) ;
if ( ret = = - 1 ) {
enum TDB_ERROR err = tdb_error ( tdb ) ;
return map_unix_error_from_tdb ( err ) ;
}
ret = tdb_fetch_talloc ( tdb , key , db , & data ) ;
if ( ret ! = 0 ) {
tdb_chainunlock ( tdb , key ) ;
return ret ;
}
2017-03-23 17:48:25 +03:00
datalen = talloc_get_size ( data ) ;
if ( ( datalen = = 0 ) | | ( data [ datalen - 1 ] ! = ' \0 ' ) ) {
tdb_chainunlock ( tdb , key ) ;
TALLOC_FREE ( data ) ;
return EINVAL ;
}
2014-10-15 20:14:42 +04:00
ids = ( char * ) data ;
2015-09-29 21:24:10 +03:00
id = strv_find ( ids , idbuf ) ;
2014-10-15 20:14:42 +04:00
if ( id = = NULL ) {
tdb_chainunlock ( tdb , key ) ;
TALLOC_FREE ( data ) ;
return ENOENT ;
}
strv_delete ( & ids , id ) ;
2017-03-23 17:48:25 +03:00
if ( talloc_get_size ( ids ) = = 0 ) {
ret = tdb_delete ( tdb , key ) ;
} else {
ret = tdb_store ( tdb , key , talloc_tdb_data ( ids ) , TDB_MODIFY ) ;
}
2014-10-15 20:14:42 +04:00
TALLOC_FREE ( data ) ;
tdb_chainunlock ( tdb , key ) ;
2015-04-26 12:02:27 +03:00
return 0 ;
}
int server_id_db_remove ( struct server_id_db * db , const char * name )
{
char * n ;
int ret ;
n = strv_find ( db - > names , name ) ;
if ( n = = NULL ) {
return ENOENT ;
}
ret = server_id_db_prune_name ( db , name , db - > pid ) ;
if ( ret ! = 0 ) {
return ret ;
2014-10-15 20:14:42 +04:00
}
strv_delete ( & db - > names , n ) ;
return 0 ;
}
int server_id_db_lookup ( struct server_id_db * db , const char * name ,
TALLOC_CTX * mem_ctx , unsigned * pnum_servers ,
struct server_id * * pservers )
{
struct tdb_context * tdb = db - > tdb - > tdb ;
TDB_DATA key ;
uint8_t * data ;
2017-03-23 17:48:25 +03:00
size_t datalen ;
2014-10-15 20:14:42 +04:00
char * ids , * id ;
unsigned num_servers ;
struct server_id * servers ;
int i , ret ;
key = string_term_tdb_data ( name ) ;
ret = tdb_fetch_talloc ( tdb , key , mem_ctx , & data ) ;
if ( ret ! = 0 ) {
return ret ;
}
2017-03-23 17:48:25 +03:00
datalen = talloc_get_size ( data ) ;
if ( ( datalen = = 0 ) | | ( data [ datalen - 1 ] ! = ' \0 ' ) ) {
TALLOC_FREE ( data ) ;
return EINVAL ;
}
2014-10-15 20:14:42 +04:00
ids = ( char * ) data ;
num_servers = strv_count ( ids ) ;
servers = talloc_array ( mem_ctx , struct server_id , num_servers ) ;
if ( servers = = NULL ) {
TALLOC_FREE ( data ) ;
return ENOMEM ;
}
i = 0 ;
for ( id = ids ; id ! = NULL ; id = strv_next ( ids , id ) ) {
servers [ i + + ] = server_id_from_string ( NONCLUSTER_VNN , id ) ;
}
TALLOC_FREE ( data ) ;
* pnum_servers = num_servers ;
* pservers = servers ;
return 0 ;
}
bool server_id_db_lookup_one ( struct server_id_db * db , const char * name ,
struct server_id * server )
{
int ret ;
unsigned num_servers ;
struct server_id * servers ;
ret = server_id_db_lookup ( db , name , db , & num_servers , & servers ) ;
if ( ret ! = 0 ) {
return false ;
}
if ( num_servers = = 0 ) {
TALLOC_FREE ( servers ) ;
return false ;
}
* server = servers [ 0 ] ;
TALLOC_FREE ( servers ) ;
return true ;
}
struct server_id_db_traverse_state {
TALLOC_CTX * mem_ctx ;
int ( * fn ) ( const char * name ,
unsigned num_servers ,
const struct server_id * servers ,
void * private_data ) ;
void * private_data ;
} ;
static int server_id_db_traverse_fn ( struct tdb_context * tdb ,
TDB_DATA key , TDB_DATA data ,
void * private_data )
{
struct server_id_db_traverse_state * state = private_data ;
const char * name ;
char * ids , * id ;
unsigned num_servers ;
struct server_id * servers ;
int i , ret ;
if ( key . dsize = = 0 ) {
return 0 ;
}
if ( key . dptr [ key . dsize - 1 ] ! = ' \0 ' ) {
return 0 ;
}
name = ( const char * ) key . dptr ;
ids = ( char * ) talloc_memdup ( state - > mem_ctx , data . dptr , data . dsize ) ;
if ( ids = = NULL ) {
return 0 ;
}
num_servers = strv_count ( ids ) ;
servers = talloc_array ( ids , struct server_id , num_servers ) ;
i = 0 ;
for ( id = ids ; id ! = NULL ; id = strv_next ( ids , id ) ) {
servers [ i + + ] = server_id_from_string ( NONCLUSTER_VNN , id ) ;
}
ret = state - > fn ( name , num_servers , servers , state - > private_data ) ;
TALLOC_FREE ( ids ) ;
return ret ;
}
int server_id_db_traverse_read ( struct server_id_db * db ,
int ( * fn ) ( const char * name ,
unsigned num_servers ,
const struct server_id * servers ,
void * private_data ) ,
void * private_data )
{
struct server_id_db_traverse_state state ;
int ret ;
state = ( struct server_id_db_traverse_state ) {
. fn = fn , . private_data = private_data ,
. mem_ctx = talloc_new ( db )
} ;
if ( state . mem_ctx = = NULL ) {
return ENOMEM ;
}
ret = tdb_traverse_read ( db - > tdb - > tdb , server_id_db_traverse_fn ,
& state ) ;
TALLOC_FREE ( state . mem_ctx ) ;
return ret ;
}