namedbname.c: Fixed *nasty* bug that caused nmbd to spin and eat memory
[kai/samba.git] / source3 / namedbname.c
index 0ec8cdbbbe581a2a20c504c4406f5c8faeeb2c7a..2e0afc1497baee4a0815a5895d1dba775dbfaf9c 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    NBT netbios routines and daemon - version 2
-   Copyright (C) Andrew Tridgell 1994-1996
+   Copyright (C) Andrew Tridgell 1994-1997
    
    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
@@ -35,7 +35,7 @@ extern int DEBUGLEVEL;
 
 extern pstring scope;
 extern struct in_addr ipzero;
-extern struct in_addr ipgrp;
+extern struct in_addr wins_ip;
 
 extern struct subnet_record *subnetlist;
 
@@ -140,8 +140,7 @@ void remove_name(struct subnet_record *d, struct name_record *n)
   find a name in a namelist.
   **************************************************************************/
 struct name_record *find_name(struct name_record *n,
-                       struct nmb_name *name,
-                       int search)
+                       struct nmb_name *name, int search)
 {
        struct name_record *ret;
   
@@ -150,13 +149,15 @@ struct name_record *find_name(struct name_record *n,
                if (name_equal(&ret->name,name))
                {
                        /* self search: self names only */
-                       if ((search&FIND_SELF) == FIND_SELF && 
-                           ret->source != SELF)
+                       if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF)
+                       {
                                continue;
-         
+                       }
+                       DEBUG(9,("find_name: found name %s\n", name->name));
                        return ret;
                }
        }
+    DEBUG(9,("find_name: name %s NOT FOUND\n", name->name));
     return NULL;
 }
 
@@ -172,27 +173,27 @@ struct name_record *find_name_search(struct subnet_record **d,
                        struct nmb_name *name,
                        int search, struct in_addr ip)
 {
-       if (d == NULL) return NULL; /* bad error! */
+  if (d == NULL) return NULL; /* bad error! */
        
-    if (search & FIND_LOCAL) {
-      if (*d != NULL) {
-       struct name_record *n = find_name((*d)->namelist, name, search);
-       DEBUG(4,("find_name on local: %s %s search %x\n",
-                namestr(name),inet_ntoa(ip), search));
-       if (n) return n;
-      }
+  if (search & FIND_LOCAL) {
+    if (*d != NULL) {
+      struct name_record *n = find_name((*d)->namelist, name, search);
+      DEBUG(4,("find_name on local: %s %s search %x\n",
+              namestr(name),inet_ntoa(ip), search));
+      if (n) return n;
     }
+  }
 
-    if (!(search & FIND_WINS)) return NULL;
+  if (!(search & FIND_WINS)) return NULL;
 
-    /* find WINS subnet record. */
-    *d = find_subnet(ipgrp);
-    
-    if (*d == NULL) return NULL;
-    
-    DEBUG(4,("find_name on WINS: %s %s search %x\n",
-            namestr(name),inet_ntoa(ip), search));
-    return find_name((*d)->namelist, name, search);
+  /* find WINS subnet record. */
+  *d = wins_subnet;
+  
+  if (*d == NULL) return NULL;
+  
+  DEBUG(4,("find_name on WINS: %s %s search %x\n",
+          namestr(name),inet_ntoa(ip), search));
+  return find_name((*d)->namelist, name, search);
 }
 
 
@@ -202,12 +203,14 @@ struct name_record *find_name_search(struct subnet_record **d,
 void dump_names(void)
 {
   struct name_record *n;
-  struct subnet_record *d;
   fstring fname, fnamenew;
   time_t t = time(NULL);
   
   FILE *f;
-  
+  if(lp_wins_support() == False || wins_subnet == 0)
+    return;
   strcpy(fname,lp_lockdir());
   trim_string(fname,NULL,"/");
   strcat(fname,"/");
@@ -219,32 +222,32 @@ void dump_names(void)
   
   if (!f)
   {
-    DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+    DEBUG(3,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+    return;
   }
   
-  DEBUG(3,("Dump of local name table:\n"));
+  DEBUG(4,("Dump of WINS name table:\n"));
   
-  for (d = subnetlist; d; d = d->next)
-   for (n = d->namelist; n; n = n->next)
-    {
-      int i;
+  for (n = wins_subnet->namelist; n; n = n->next)
+   {
+     int i;
 
-         DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
-         DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
-      DEBUG(3,("%-19s TTL=%ld ",
+     DEBUG(4,("%15s ", inet_ntoa(wins_subnet->bcast_ip)));
+     DEBUG(4,("%15s ", inet_ntoa(wins_subnet->mask_ip)));
+     DEBUG(4,("%-19s TTL=%ld ",
               namestr(&n->name),
               n->death_time?n->death_time-t:0));
 
-        for (i = 0; i < n->num_ips; i++)
-        {
-           DEBUG(3,("%15s NB=%2x source=%d",
-                   inet_ntoa(n->ip_flgs[i].ip),
+     for (i = 0; i < n->num_ips; i++)
+      {
+        DEBUG(4,("%15s NB=%2x source=%d",
+                 inet_ntoa(n->ip_flgs[i].ip),
                    n->ip_flgs[i].nb_flags,n->source));
 
-        }
-               DEBUG(3,("\n"));
+      }
+     DEBUG(4,("\n"));
 
-      if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER)
+     if (f && n->source == REGISTER)
       {
       /* XXXX i have little imagination as to how to output nb_flags as
          anything other than as a hexadecimal number :-) */
@@ -262,7 +265,7 @@ void dump_names(void)
                fprintf(f, "\n");
       }
 
-    }
+  }
 
   fclose(f);
   unlink(fname);
@@ -280,7 +283,7 @@ void dump_names(void)
   ****************************************************************************/
 void load_netbios_names(void)
 {
-  struct subnet_record *d = find_subnet(ipgrp);
+  struct subnet_record *d = wins_subnet;
   fstring fname;
 
   FILE *f;
@@ -412,11 +415,18 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
 {
   struct name_record *n;
   struct name_record *n2=NULL;
+  struct subnet_record *found_subnet = 0;
   int search = 0;
   BOOL self = source == SELF;
 
   /* add the name to the WINS list if the name comes from a directed query */
   search |= wins ? FIND_WINS : FIND_LOCAL;
+
+  /* If it's a local search then we need to set the subnet
+     we are looking at. */
+  if(search & FIND_LOCAL)
+    found_subnet = d;
+
   /* search for SELF names only */
   search |= self ? FIND_SELF : 0;
 
@@ -445,12 +455,13 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
 
   make_nmb_name(&n->name,name,type,scope);
 
-  if ((n2 = find_name_search(&d, &n->name, search, new_only?ipzero:ip)))
+  if ((n2 = find_name_search(&found_subnet, &n->name, search, new_only?ipzero:ip)))
   {
     free(n->ip_flgs);
     free(n);
     if (new_only || (n2->source==SELF && source!=SELF)) return n2;
     n = n2;
+    d = found_subnet;
   }
 
   if (ttl)
@@ -465,8 +476,9 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
   
   if (!n2) add_name(d,n);
 
-  DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n",
-               namestr(&n->name),inet_ntoa(ip),ttl,nb_flags));
+  DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x to interface %s\n",
+          namestr(&n->name),inet_ntoa(ip),ttl,nb_flags,
+          ip_equal(d->bcast_ip, wins_ip) ? "WINS" : (char *)inet_ntoa(d->bcast_ip)));
 
   return(n);
 }
@@ -482,7 +494,7 @@ void expire_names(time_t t)
        struct subnet_record *d;
 
        /* expire old names */
-       for (d = subnetlist; d; d = d->next)
+       for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
        {
          for (n = d->namelist; n; n = next)
            {
@@ -510,77 +522,44 @@ void expire_names(time_t t)
 
 
 /***************************************************************************
-  reply to a name query
+  assume a WINS name is a dns name, and do a gethostbyname() on it.
   ****************************************************************************/
-struct name_record *search_for_name(struct subnet_record **d,
-                                   struct nmb_name *question,
-                                   struct in_addr ip, int Time, int search)
+struct name_record *dns_name_search(struct nmb_name *question, int Time)
 {
-  int name_type = question->name_type;
-  char *qname = question->name;
-  BOOL dns_type = (name_type == 0x20 || name_type == 0);
-  
-  struct name_record *n;
-  
-  DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
-  
-  /* first look up name in cache */
-  n = find_name_search(d,question,search,ip);
-  
-  if (*d == NULL) return NULL;
+       int name_type = question->name_type;
+       char *qname = question->name;
+       char *r;
+       BOOL dns_type = (name_type == 0x20 || name_type == 0);
+       struct in_addr dns_ip;
 
-  /* now try DNS lookup. */
-  if (!n)
-    {
-      struct in_addr dns_ip;
-      uint32 a;      
-      
-      /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
-      if (!dns_type && name_type != 0x1b)
+       if (wins_subnet == NULL) 
+          return NULL;
+
+       DEBUG(3,("Search for %s - ", namestr(question)));
+
+       /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
+       if (!dns_type)
        {
-         DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n"));
-         return NULL;
+               DEBUG(3,("types 0x20 0x0 only: name not found\n"));
+               return NULL;
        }
-      
-      /* look it up with DNS */      
-      a = interpret_addr(qname);
-      
-      putip((char *)&dns_ip,(char *)&a);
-      
-      if (!a)
+
+       /* look it up with DNS */      
+       dns_ip.s_addr = interpret_addr(qname);
+
+       if (!dns_ip.s_addr)
        {
-         /* no luck with DNS. We could possibly recurse here XXXX */
-         DEBUG(3,("no recursion.\n"));
-      /* add the fail to our WINS cache of names. give it 1 hour in the cache */
-         add_netbios_entry(*d,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,
-                                               True, True);
-         return NULL;
+               /* no luck with DNS. We could possibly recurse here XXXX */
+               DEBUG(3,("not found. no recursion.\n"));
+               /* add the fail to WINS cache of names. give it 1 hour in the cache */
+               add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,
+                                 True, True);
+               return NULL;
        }
-      
-      /* add it to our WINS cache of names. give it 2 hours in the cache */
-      n = add_netbios_entry(*d,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,
-                                               True,True);
-      
-      /* failed to add it? yikes! */
-      if (!n) return NULL;
-    }
-  
-  /* is our entry already dead? */
-  if (n->death_time)
-    {
-      if (n->death_time < Time) return False;
-    }
-  
-  /* it may have been an earlier failure */
-  if (n->source == DNSFAIL)
-    {
-      DEBUG(3,("DNSFAIL\n"));
-      return NULL;
-    }
-  
-  DEBUG(3,("OK %s\n",inet_ntoa(n->ip_flgs[0].ip)));      
-  
-  return n;
-}
 
+       DEBUG(3,("found with DNS: %s\n", inet_ntoa(dns_ip)));
 
+       /* add it to our WINS cache of names. give it 2 hours in the cache */
+       return add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,
+                                True,True);
+}