/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998
*/
#include "includes.h"
-#include "smb.h"
extern int ClientNMB;
extern int ClientDGRAM;
extern int global_nmb_port;
-extern int DEBUGLEVEL;
-
-extern fstring myworkgroup;
-extern char **my_netbios_names;
-extern struct in_addr ipzero;
-
/* This is the broadcast subnets database. */
struct subnet_record *subnetlist = NULL;
static void add_subnet(struct subnet_record *subrec)
{
- struct subnet_record *subrec2;
-
- if (!subnetlist)
- {
- subnetlist = subrec;
- subrec->prev = NULL;
- subrec->next = NULL;
- return;
- }
-
- for (subrec2 = subnetlist; subrec2->next; subrec2 = subrec2->next)
- ;
-
- subrec2->next = subrec;
- subrec->next = NULL;
- subrec->prev = subrec2;
+ DLIST_ADD(subnetlist, subrec);
}
/* ************************************************************************** **
* ************************************************************************** **
*/
static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
- {
- struct name_record *NR = (struct name_record *)Node;
+{
+ struct name_record *NR = (struct name_record *)Node;
- if( DEBUGLVL( 10 ) )
- {
- struct nmb_name *Iname = (struct nmb_name *)Item;
+ if( DEBUGLVL( 10 ) ) {
+ struct nmb_name *Iname = (struct nmb_name *)Item;
- Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" );
- Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n",
- memcmp( Item, &(NR->name), sizeof(struct nmb_name) ),
- nmb_namestr(Iname), nmb_namestr(&NR->name), sizeof(struct nmb_name) );
- }
+ Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" );
+ Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n",
+ memcmp( Item, &(NR->name), sizeof(struct nmb_name) ),
+ nmb_namestr(Iname), nmb_namestr(&NR->name), (int)sizeof(struct nmb_name) );
+ }
+
+ return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
+}
- return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
- } /* namelist_entry_compare */
+/****************************************************************************
+stop listening on a subnet
+we don't free the record as we don't have proper reference counting for it
+yet and it may be in use by a response record
+ ****************************************************************************/
+
+void close_subnet(struct subnet_record *subrec)
+{
+ DLIST_REMOVE(subnetlist, subrec);
+
+ if (subrec->dgram_sock != -1) {
+ close(subrec->dgram_sock);
+ subrec->dgram_sock = -1;
+ }
+ if (subrec->nmb_sock != -1) {
+ close(subrec->nmb_sock);
+ subrec->nmb_sock = -1;
+ }
+}
/****************************************************************************
Create a subnet entry.
****************************************************************************/
-static struct subnet_record *make_subnet(char *name, enum subnet_type type,
- struct in_addr myip, struct in_addr bcast_ip,
- struct in_addr mask_ip)
+static struct subnet_record *make_subnet(const char *name, enum subnet_type type,
+ struct in_addr myip, struct in_addr bcast_ip,
+ struct in_addr mask_ip)
{
- struct subnet_record *subrec = NULL;
- int nmb_sock, dgram_sock;
-
- /* Check if we are creating a non broadcast subnet - if so don't create
- sockets.
- */
-
- if(type != NORMAL_SUBNET)
- {
- nmb_sock = -1;
- dgram_sock = -1;
- }
- else
- {
- /*
- * Attempt to open the sockets on port 137/138 for this interface
- * and bind them.
- * Fail the subnet creation if this fails.
- */
-
- if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr)) == -1)
- {
- if( DEBUGLVL( 0 ) )
- {
- Debug1( "nmbd_subnetdb:make_subnet()\n" );
- Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
- Debug1( "for port %d. ", global_nmb_port );
- Debug1( "Error was %s\n", strerror(errno) );
- }
- return NULL;
- }
-
- if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr)) == -1)
- {
- if( DEBUGLVL( 0 ) )
- {
- Debug1( "nmbd_subnetdb:make_subnet()\n" );
- Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
- Debug1( "for port %d. ", DGRAM_PORT );
- Debug1( "Error was %s\n", strerror(errno) );
- }
- return NULL;
- }
-
- /* Make sure we can broadcast from these sockets. */
- set_socket_options(nmb_sock,"SO_BROADCAST");
- set_socket_options(dgram_sock,"SO_BROADCAST");
-
- }
-
- subrec = (struct subnet_record *)malloc(sizeof(*subrec));
-
- if (!subrec)
- {
- DEBUG(0,("make_subnet: malloc fail !\n"));
- close(nmb_sock);
- close(dgram_sock);
- return(NULL);
- }
+ struct subnet_record *subrec = NULL;
+ int nmb_sock, dgram_sock;
+
+ /* Check if we are creating a non broadcast subnet - if so don't create
+ sockets. */
+
+ if(type != NORMAL_SUBNET) {
+ nmb_sock = -1;
+ dgram_sock = -1;
+ } else {
+ /*
+ * Attempt to open the sockets on port 137/138 for this interface
+ * and bind them.
+ * Fail the subnet creation if this fails.
+ */
+
+ if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1) {
+ if( DEBUGLVL( 0 ) ) {
+ Debug1( "nmbd_subnetdb:make_subnet()\n" );
+ Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
+ Debug1( "for port %d. ", global_nmb_port );
+ Debug1( "Error was %s\n", strerror(errno) );
+ }
+ return NULL;
+ }
+
+ if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1) {
+ if( DEBUGLVL( 0 ) ) {
+ Debug1( "nmbd_subnetdb:make_subnet()\n" );
+ Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
+ Debug1( "for port %d. ", DGRAM_PORT );
+ Debug1( "Error was %s\n", strerror(errno) );
+ }
+ return NULL;
+ }
+
+ /* Make sure we can broadcast from these sockets. */
+ set_socket_options(nmb_sock,"SO_BROADCAST");
+ set_socket_options(dgram_sock,"SO_BROADCAST");
+ }
+
+ subrec = (struct subnet_record *)malloc(sizeof(*subrec));
+ if (!subrec) {
+ DEBUG(0,("make_subnet: malloc fail !\n"));
+ close(nmb_sock);
+ close(dgram_sock);
+ return(NULL);
+ }
- bzero( (char *)subrec, sizeof(*subrec) );
- (void)ubi_trInitTree( subrec->namelist,
- namelist_entry_compare,
- ubi_trOVERWRITE );
-
- if((subrec->subnet_name = strdup(name)) == NULL)
- {
- DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
- close(nmb_sock);
- close(dgram_sock);
- ZERO_STRUCTP(subrec);
- free((char *)subrec);
- return(NULL);
- }
-
- DEBUG(2, ("making subnet name:%s ", name ));
- DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
- DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
+ memset( (char *)subrec, '\0', sizeof(*subrec) );
+ (void)ubi_trInitTree( subrec->namelist,
+ namelist_entry_compare,
+ ubi_trOVERWRITE );
+
+ if((subrec->subnet_name = strdup(name)) == NULL) {
+ DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
+ close(nmb_sock);
+ close(dgram_sock);
+ ZERO_STRUCTP(subrec);
+ SAFE_FREE(subrec);
+ return(NULL);
+ }
+
+ DEBUG(2, ("making subnet name:%s ", name ));
+ DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
+ DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
- subrec->namelist_changed = False;
- subrec->work_changed = False;
+ subrec->namelist_changed = False;
+ subrec->work_changed = False;
- subrec->bcast_ip = bcast_ip;
- subrec->mask_ip = mask_ip;
- subrec->myip = myip;
- subrec->type = type;
- subrec->nmb_sock = nmb_sock;
- subrec->dgram_sock = dgram_sock;
+ subrec->bcast_ip = bcast_ip;
+ subrec->mask_ip = mask_ip;
+ subrec->myip = myip;
+ subrec->type = type;
+ subrec->nmb_sock = nmb_sock;
+ subrec->dgram_sock = dgram_sock;
- return subrec;
+ return subrec;
+}
+
+/****************************************************************************
+ Create a normal subnet
+**************************************************************************/
+
+struct subnet_record *make_normal_subnet(struct interface *iface)
+{
+ struct subnet_record *subrec;
+
+ subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
+ iface->ip, iface->bcast, iface->nmask);
+ if (subrec) {
+ add_subnet(subrec);
+ }
+ return subrec;
}
/****************************************************************************
BOOL create_subnets(void)
{
- int num_interfaces = iface_count();
- int i;
- struct in_addr unicast_ip;
-
- if(num_interfaces == 0)
- {
- DEBUG(0,("create_subnets: No local interfaces !\n"));
- return False;
- }
-
- /*
- * Create subnets from all the local interfaces and thread them onto
- * the linked list.
- */
-
- for (i = 0 ; i < num_interfaces; i++)
- {
- struct subnet_record *subrec;
- struct interface *iface = get_interface(i);
-
- if((subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
- iface->ip, iface->bcast,iface->nmask)) == NULL)
- return False;
- add_subnet(subrec);
- }
-
- /*
- * If we have been configured to use a WINS server, then try and
- * get the ip address of it here. If we are the WINS server then
- * set the unicast subnet address to be the first of our own real
- * addresses.
- */
-
- if(*lp_wins_server())
- {
- struct in_addr real_wins_ip;
- real_wins_ip = *interpret_addr2(lp_wins_server());
-
- if (!zero_ip(real_wins_ip))
- {
- unicast_ip = real_wins_ip;
- }
- else
- {
- /* The smb.conf's wins server parameter MUST be a host_name
- or an ip_address. */
- DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
- return False;
- }
- }
- else if(lp_we_are_a_wins_server())
- {
- /* Pick the first interface ip address as the WINS server ip. */
- unicast_ip = *iface_n_ip(0);
- }
- else
- {
- /* We should not be using a WINS server at all. Set the
- ip address of the subnet to be zero. */
- unicast_ip = ipzero;
- }
-
- /*
- * Create the unicast and remote broadcast subnets.
- * Don't put these onto the linked list.
- * The ip address of the unicast subnet is set to be
- * the WINS server address, if it exists, or ipzero if not.
- */
-
- unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
- unicast_ip, unicast_ip, unicast_ip);
-
- remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
- REMOTE_BROADCAST_SUBNET,
- ipzero, ipzero, ipzero);
-
- if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
- return False;
-
- /*
- * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
- * the linked list.
- */
-
- if (lp_we_are_a_wins_server())
- {
- if((wins_server_subnet = make_subnet("WINS_SERVER_SUBNET",
- WINS_SERVER_SUBNET,
- ipzero, ipzero, ipzero)) == NULL)
- return False;
- }
-
- return True;
+ int num_interfaces = iface_count();
+ int i;
+ struct in_addr unicast_ip, ipzero;
+ extern struct in_addr loopback_ip;
+
+ if(num_interfaces == 0) {
+ DEBUG(0,("create_subnets: No local interfaces !\n"));
+ DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
+ while (iface_count() == 0) {
+ sleep(5);
+ load_interfaces();
+ }
+ }
+
+ num_interfaces = iface_count();
+
+ /*
+ * Create subnets from all the local interfaces and thread them onto
+ * the linked list.
+ */
+
+ for (i = 0 ; i < num_interfaces; i++) {
+ struct interface *iface = get_interface(i);
+
+ /*
+ * We don't want to add a loopback interface, in case
+ * someone has added 127.0.0.1 for smbd, nmbd needs to
+ * ignore it here. JRA.
+ */
+
+ if (ip_equal(iface->ip, loopback_ip)) {
+ DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
+ continue;
+ }
+
+ if (!make_normal_subnet(iface))
+ return False;
+ }
+
+ if (lp_we_are_a_wins_server()) {
+ /* Pick the first interface ip address as the WINS server ip. */
+ unicast_ip = *iface_n_ip(0);
+ } else {
+ /* note that we do not set the wins server IP here. We just
+ set it at zero and let the wins registration code cope
+ with getting the IPs right for each packet */
+ zero_ip(&unicast_ip);
+ }
+
+ /*
+ * Create the unicast and remote broadcast subnets.
+ * Don't put these onto the linked list.
+ * The ip address of the unicast subnet is set to be
+ * the WINS server address, if it exists, or ipzero if not.
+ */
+
+ unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
+ unicast_ip, unicast_ip, unicast_ip);
+
+ zero_ip(&ipzero);
+
+ remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
+ REMOTE_BROADCAST_SUBNET,
+ ipzero, ipzero, ipzero);
+
+ if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
+ return False;
+
+ /*
+ * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
+ * the linked list.
+ */
+
+ if (lp_we_are_a_wins_server()) {
+ if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
+ WINS_SERVER_SUBNET,
+ ipzero, ipzero, ipzero )) == NULL )
+ return False;
+ }
+
+ return True;
}
/*******************************************************************
BOOL we_are_a_wins_client(void)
{
- static int cache_we_are_a_wins_client = -1;
-
- if(cache_we_are_a_wins_client == -1)
- cache_we_are_a_wins_client = (ip_equal(ipzero, unicast_subnet->myip) ?
- False : True);
+ if (wins_srv_count() > 0) {
+ return True;
+ }
- return cache_we_are_a_wins_client;
+ return False;
}
/*******************************************************************
struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
{
- if(subrec == unicast_subnet)
- return NULL;
- else if((subrec->next == NULL) && we_are_a_wins_client())
- return unicast_subnet;
- else
- return subrec->next;
+ if(subrec == unicast_subnet)
+ return NULL;
+ else if((subrec->next == NULL) && we_are_a_wins_client())
+ return unicast_subnet;
+ else
+ return subrec->next;
}
/*******************************************************************
struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
{
- if(subrec == unicast_subnet)
- {
- if(wins_server_subnet)
- return wins_server_subnet;
- else
- return NULL;
- }
-
- if(wins_server_subnet && subrec == wins_server_subnet)
- return NULL;
-
- if((subrec->next == NULL) && we_are_a_wins_client())
- return unicast_subnet;
- else
- return subrec->next;
+ if(subrec == unicast_subnet) {
+ if(wins_server_subnet)
+ return wins_server_subnet;
+ else
+ return NULL;
+ }
+
+ if(wins_server_subnet && subrec == wins_server_subnet)
+ return NULL;
+
+ if((subrec->next == NULL) && we_are_a_wins_client())
+ return unicast_subnet;
+ else
+ return subrec->next;
}