2005-01-31 04:57:58 +03:00
/*
Unix SMB / CIFS implementation .
core wins server handling
Copyright ( C ) Andrew Tridgell 2005
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "nbt_server/nbt_server.h"
2005-02-19 02:53:52 +03:00
# include "nbt_server/wins/winsdb.h"
2005-02-12 14:33:42 +03:00
# include "system/time.h"
2005-07-19 13:28:46 +04:00
# include "smbd/service_task.h"
2005-01-31 04:57:58 +03:00
2005-02-14 12:15:24 +03:00
/*
work out the ttl we will use given a client requested ttl
*/
uint32_t wins_server_ttl ( struct wins_server * winssrv , uint32_t ttl )
{
ttl = MIN ( ttl , winssrv - > max_ttl ) ;
ttl = MAX ( ttl , winssrv - > min_ttl ) ;
return ttl ;
}
2005-02-12 14:33:42 +03:00
/*
register a new name with WINS
*/
static uint8_t wins_register_new ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
2005-10-14 16:22:15 +04:00
const struct nbt_peer_socket * src )
2005-02-12 14:33:42 +03:00
{
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private ,
struct nbtd_interface ) ;
struct wins_server * winssrv = iface - > nbtsrv - > winssrv ;
struct nbt_name * name = & packet - > questions [ 0 ] . name ;
2005-02-14 12:15:24 +03:00
uint32_t ttl = wins_server_ttl ( winssrv , packet - > additional [ 0 ] . ttl ) ;
2005-02-14 08:00:22 +03:00
uint16_t nb_flags = packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . nb_flags ;
const char * address = packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . ipaddr ;
2005-02-12 14:33:42 +03:00
struct winsdb_record rec ;
rec . name = name ;
2005-02-14 08:00:22 +03:00
rec . nb_flags = nb_flags ;
2005-02-12 14:33:42 +03:00
rec . state = WINS_REC_ACTIVE ;
rec . expire_time = time ( NULL ) + ttl ;
2005-10-14 16:22:15 +04:00
rec . registered_by = src - > addr ;
2005-02-15 14:14:04 +03:00
if ( IS_GROUP_NAME ( name , nb_flags ) ) {
2005-02-14 08:00:22 +03:00
rec . addresses = str_list_make ( packet , " 255.255.255.255 " , NULL ) ;
} else {
rec . addresses = str_list_make ( packet , address , NULL ) ;
}
if ( rec . addresses = = NULL ) return NBT_RCODE_SVR ;
DEBUG ( 4 , ( " WINS: accepted registration of %s with address %s \n " ,
nbt_name_string ( packet , name ) , rec . addresses [ 0 ] ) ) ;
2005-02-12 14:33:42 +03:00
return winsdb_add ( winssrv , & rec ) ;
}
2005-02-12 02:54:37 +03:00
2005-02-12 04:00:15 +03:00
2005-02-14 08:00:22 +03:00
/*
update the ttl on an existing record
*/
static uint8_t wins_update_ttl ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
struct winsdb_record * rec ,
2005-10-14 16:22:15 +04:00
const struct nbt_peer_socket * src )
2005-02-14 08:00:22 +03:00
{
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private ,
struct nbtd_interface ) ;
struct wins_server * winssrv = iface - > nbtsrv - > winssrv ;
2005-02-14 12:15:24 +03:00
uint32_t ttl = wins_server_ttl ( winssrv , packet - > additional [ 0 ] . ttl ) ;
2005-02-14 08:00:22 +03:00
const char * address = packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . ipaddr ;
time_t now = time ( NULL ) ;
if ( now + ttl > rec - > expire_time ) {
rec - > expire_time = now + ttl ;
}
2005-10-14 16:22:15 +04:00
rec - > registered_by = src - > addr ;
2005-02-14 08:00:22 +03:00
DEBUG ( 5 , ( " WINS: refreshed registration of %s at %s \n " ,
nbt_name_string ( packet , rec - > name ) , address ) ) ;
return winsdb_modify ( winssrv , rec ) ;
}
2005-02-12 14:33:42 +03:00
/*
register a name
*/
static void nbtd_winsserver_register ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
2005-10-14 16:22:15 +04:00
const struct nbt_peer_socket * src )
2005-02-12 14:33:42 +03:00
{
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private ,
struct nbtd_interface ) ;
struct wins_server * winssrv = iface - > nbtsrv - > winssrv ;
struct nbt_name * name = & packet - > questions [ 0 ] . name ;
struct winsdb_record * rec ;
2005-02-14 08:00:22 +03:00
uint8_t rcode = NBT_RCODE_OK ;
uint16_t nb_flags = packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . nb_flags ;
const char * address = packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . ipaddr ;
2005-02-12 14:33:42 +03:00
2005-02-14 15:46:03 +03:00
/* as a special case, the local master browser name is always accepted
for registration , but never stored */
if ( name - > type = = NBT_NAME_MASTER ) {
goto done ;
}
2005-02-12 14:33:42 +03:00
rec = winsdb_load ( winssrv , name , packet ) ;
if ( rec = = NULL ) {
2005-10-14 16:22:15 +04:00
rcode = wins_register_new ( nbtsock , packet , src ) ;
2005-02-14 08:00:22 +03:00
goto done ;
2005-02-12 14:33:42 +03:00
} else if ( rec - > state ! = WINS_REC_ACTIVE ) {
2005-02-16 18:19:49 +03:00
winsdb_delete ( winssrv , rec ) ;
2005-10-14 16:22:15 +04:00
rcode = wins_register_new ( nbtsock , packet , src ) ;
2005-02-14 08:00:22 +03:00
goto done ;
}
/* its an active name - first see if the registration is of the right type */
if ( ( rec - > nb_flags & NBT_NM_GROUP ) & & ! ( nb_flags & NBT_NM_GROUP ) ) {
DEBUG ( 2 , ( " WINS: Attempt to register unique name %s when group name is active \n " ,
nbt_name_string ( packet , name ) ) ) ;
2005-02-12 14:33:42 +03:00
rcode = NBT_RCODE_ACT ;
2005-02-14 08:00:22 +03:00
goto done ;
}
/* if its an active unique name, and the registration is for a group, then
see if the unique name owner still wants the name */
if ( ! ( rec - > nb_flags & NBT_NM_GROUP ) & & ( nb_flags & NBT_NM_GROUP ) ) {
2005-10-14 16:22:15 +04:00
wins_register_wack ( nbtsock , packet , rec , src ) ;
2005-02-14 08:00:22 +03:00
return ;
2005-02-12 14:33:42 +03:00
}
2005-02-14 08:00:22 +03:00
/* if the registration is for a group, then just update the expiry time
and we are done */
2005-02-15 14:14:04 +03:00
if ( IS_GROUP_NAME ( name , nb_flags ) ) {
2005-10-14 16:22:15 +04:00
wins_update_ttl ( nbtsock , packet , rec , src ) ;
2005-02-14 08:00:22 +03:00
goto done ;
}
/* if the registration is for an address that is currently active, then
just update the expiry time */
2005-02-14 12:15:24 +03:00
if ( str_list_check ( rec - > addresses , address ) ) {
2005-10-14 16:22:15 +04:00
wins_update_ttl ( nbtsock , packet , rec , src ) ;
2005-02-14 12:15:24 +03:00
goto done ;
2005-02-14 08:00:22 +03:00
}
2005-02-14 12:15:24 +03:00
/* we have to do a WACK to see if the current owner is willing
to give up its claim */
2005-10-14 16:22:15 +04:00
wins_register_wack ( nbtsock , packet , rec , src ) ;
2005-02-14 08:00:22 +03:00
return ;
done :
2005-10-14 16:22:15 +04:00
nbtd_name_registration_reply ( nbtsock , packet , src , rcode ) ;
2005-02-12 14:33:42 +03:00
}
/*
query a name
*/
2005-02-12 02:54:37 +03:00
static void nbtd_winsserver_query ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
2005-10-14 16:22:15 +04:00
const struct nbt_peer_socket * src )
2005-02-12 02:54:37 +03:00
{
2005-02-12 14:33:42 +03:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private ,
struct nbtd_interface ) ;
struct wins_server * winssrv = iface - > nbtsrv - > winssrv ;
struct nbt_name * name = & packet - > questions [ 0 ] . name ;
struct winsdb_record * rec ;
rec = winsdb_load ( winssrv , name , packet ) ;
if ( rec = = NULL | | rec - > state ! = WINS_REC_ACTIVE ) {
2005-10-14 16:22:15 +04:00
nbtd_negative_name_query_reply ( nbtsock , packet , src ) ;
2005-02-12 14:33:42 +03:00
return ;
}
2005-02-12 02:54:37 +03:00
2005-10-14 16:22:15 +04:00
nbtd_name_query_reply ( nbtsock , packet , src , name ,
2005-02-12 14:33:42 +03:00
0 , rec - > nb_flags , rec - > addresses ) ;
2005-02-12 02:54:37 +03:00
}
2005-02-12 14:33:42 +03:00
/*
release a name
*/
2005-02-12 02:54:37 +03:00
static void nbtd_winsserver_release ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
2005-10-14 16:22:15 +04:00
const struct nbt_peer_socket * src )
2005-02-12 02:54:37 +03:00
{
2005-02-12 14:33:42 +03:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private ,
struct nbtd_interface ) ;
struct wins_server * winssrv = iface - > nbtsrv - > winssrv ;
struct nbt_name * name = & packet - > questions [ 0 ] . name ;
struct winsdb_record * rec ;
rec = winsdb_load ( winssrv , name , packet ) ;
2005-02-14 12:15:24 +03:00
if ( rec = = NULL | |
rec - > state ! = WINS_REC_ACTIVE | |
2005-02-15 14:14:04 +03:00
IS_GROUP_NAME ( name , rec - > nb_flags ) ) {
2005-02-14 12:15:24 +03:00
goto done ;
}
/* we only allow releases from an owner - other releases are
silently ignored */
2005-10-14 16:22:15 +04:00
if ( str_list_check ( rec - > addresses , src - > addr ) ) {
2005-02-14 12:15:24 +03:00
const char * address = packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . ipaddr ;
DEBUG ( 4 , ( " WINS: released name %s at %s \n " , nbt_name_string ( rec , rec - > name ) , address ) ) ;
str_list_remove ( rec - > addresses , address ) ;
if ( rec - > addresses [ 0 ] = = NULL ) {
rec - > state = WINS_REC_RELEASED ;
}
2005-02-12 14:33:42 +03:00
winsdb_modify ( winssrv , rec ) ;
}
2005-02-14 12:15:24 +03:00
done :
2005-02-12 14:33:42 +03:00
/* we match w2k3 by always giving a positive reply to name releases. */
2005-10-14 16:22:15 +04:00
nbtd_name_release_reply ( nbtsock , packet , src , NBT_RCODE_OK ) ;
2005-02-12 02:54:37 +03:00
}
2005-01-31 04:57:58 +03:00
/*
answer a name query
*/
2005-02-12 02:54:37 +03:00
void nbtd_winsserver_request ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
2005-10-14 16:22:15 +04:00
const struct nbt_peer_socket * src )
2005-02-12 02:54:37 +03:00
{
2005-02-12 14:33:42 +03:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private ,
struct nbtd_interface ) ;
struct wins_server * winssrv = iface - > nbtsrv - > winssrv ;
if ( ( packet - > operation & NBT_FLAG_BROADCAST ) | | winssrv = = NULL ) {
2005-02-12 02:54:37 +03:00
return ;
}
switch ( packet - > operation & NBT_OPCODE ) {
case NBT_OPCODE_QUERY :
2005-10-14 16:22:15 +04:00
nbtd_winsserver_query ( nbtsock , packet , src ) ;
2005-02-12 02:54:37 +03:00
break ;
case NBT_OPCODE_REGISTER :
case NBT_OPCODE_REFRESH :
case NBT_OPCODE_REFRESH2 :
case NBT_OPCODE_MULTI_HOME_REG :
2005-10-14 16:22:15 +04:00
nbtd_winsserver_register ( nbtsock , packet , src ) ;
2005-02-12 02:54:37 +03:00
break ;
case NBT_OPCODE_RELEASE :
2005-10-14 16:22:15 +04:00
nbtd_winsserver_release ( nbtsock , packet , src ) ;
2005-02-12 02:54:37 +03:00
break ;
}
}
/*
startup the WINS server , if configured
*/
NTSTATUS nbtd_winsserver_init ( struct nbtd_server * nbtsrv )
2005-01-31 04:57:58 +03:00
{
2005-02-12 02:54:37 +03:00
if ( ! lp_wins_support ( ) ) {
2005-02-12 14:33:42 +03:00
nbtsrv - > winssrv = NULL ;
2005-02-12 02:54:37 +03:00
return NT_STATUS_OK ;
2005-01-31 20:16:45 +03:00
}
2005-02-12 02:54:37 +03:00
2005-10-14 16:47:57 +04:00
nbtsrv - > winssrv = talloc_zero ( nbtsrv , struct wins_server ) ;
2005-02-12 14:33:42 +03:00
NT_STATUS_HAVE_NO_MEMORY ( nbtsrv - > winssrv ) ;
2005-05-12 13:03:14 +04:00
nbtsrv - > winssrv - > max_ttl = lp_max_wins_ttl ( ) ;
nbtsrv - > winssrv - > min_ttl = lp_min_wins_ttl ( ) ;
2005-10-14 16:47:57 +04:00
nbtsrv - > winssrv - > wins_db = winsdb_connect ( nbtsrv - > winssrv ) ;
if ( ! nbtsrv - > winssrv - > wins_db ) {
return NT_STATUS_INTERNAL_DB_ERROR ;
}
2005-02-12 02:54:37 +03:00
2005-07-19 13:28:46 +04:00
irpc_add_name ( nbtsrv - > task - > msg_ctx , " wins_server " ) ;
2005-10-14 16:47:57 +04:00
return NT_STATUS_OK ;
2005-01-31 04:57:58 +03:00
}