hopefully handle "ready and waiting" messages in print queue output a
[kai/samba.git] / source3 / nameservresp.c
index a4cda7cdfb5a412dbcce1de5036f68f5a648372c..3349610da6e1faa52ff49ed6ec440218304fc913 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
@@ -37,7 +37,11 @@ extern int ClientNMB;
 extern int DEBUGLEVEL;
 
 extern pstring scope;
+extern fstring myworkgroup;
 extern struct in_addr ipzero;
+extern struct in_addr wins_ip;
+extern struct in_addr ipzero;
+
 
 #define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
 
@@ -46,16 +50,16 @@ extern struct in_addr ipzero;
   response for a reg release received. samba has asked a WINS server if it
   could release a name.
   **************************************************************************/
-static void response_name_release(struct subnet_record *d,
-                                                               struct packet_struct *p)
+static void response_name_release(struct nmb_name *ans_name,
+                       struct subnet_record *d, struct packet_struct *p)
 {
   struct nmb_packet *nmb = &p->packet.nmb;
-  char *name = nmb->question.question_name.name;
-  int   type = nmb->question.question_name.name_type;
+  char *name = ans_name->name;
+  int   type = ans_name->name_type;
   
   DEBUG(4,("response name release received\n"));
   
-  if (nmb->header.rcode == 0 && nmb->answers->rdata)
+  if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
   {
     /* IMPORTANT: see expire_netbios_response_entries() */
 
@@ -70,14 +74,12 @@ static void response_name_release(struct subnet_record *d,
     else
     {
       DEBUG(2,("name release for different ip! %s %s\n",
-                  inet_ntoa(found_ip),
-                  namestr(&nmb->question.question_name)));
+                  inet_ntoa(found_ip), namestr(ans_name)));
     }
   }
   else
   {
-    DEBUG(2,("name release for %s rejected!\n",
-              namestr(&nmb->question.question_name)));
+    DEBUG(2,("name release for %s rejected!\n", namestr(ans_name)));
 
     /* XXXX PANIC! what to do if it's one of samba's own names? */
 
@@ -91,16 +93,30 @@ static void response_name_release(struct subnet_record *d,
 /****************************************************************************
 response for a reg request received
 **************************************************************************/
-static void response_name_reg(struct subnet_record *d, struct packet_struct *p)
+static void response_name_reg(struct nmb_name *ans_name,
+                       struct subnet_record *d, struct packet_struct *p)
 {
   struct nmb_packet *nmb = &p->packet.nmb;
-  char *name = nmb->question.question_name.name;
-  int   type = nmb->question.question_name.name_type;
   BOOL bcast = nmb->header.nm_flags.bcast;
+  char *name = ans_name->name;
+  int   type = ans_name->name_type;
   
   DEBUG(4,("response name registration received!\n"));
   
-  if (nmb->header.rcode == 0 && nmb->answers->rdata)
+#if 1
+  /* This code is neccesitated due to bugs in earlier versions of
+     Samba (up to 1.9.16p11). They respond to a broadcast
+     name registration of WORKGROUP<1b> when they should
+     not. Hence, until these versions are gone, we should
+     treat such errors as success for this particular
+     case only. jallison@whistle.com.
+   */
+  if ( ((d != wins_client_subnet) && (nmb->header.rcode == 6) && strequal(myworkgroup, name) &&
+         (type == 0x1b)) ||
+       (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata))
+#else
+  if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+#endif
   {
     /* IMPORTANT: see expire_netbios_response_entries() */
 
@@ -114,91 +130,53 @@ static void response_name_reg(struct subnet_record *d, struct packet_struct *p)
   }
   else
   {
-    DEBUG(1,("name registration for %s rejected!\n",
-              namestr(&nmb->question.question_name)));
+    DEBUG(2,("name registration for %s rejected by ip %s!\n", 
+              namestr(ans_name), inet_ntoa(p->ip)));
 
        /* oh dear. we have problems. possibly unbecome a master browser. */
     name_unregister_work(d,name,type);
   }
 }
 
-
-/****************************************************************************
-  response from a name query announce host
-  NAME_QUERY_ANNOUNCE_HOST is dealt with here
-  ****************************************************************************/
-static void response_announce_host(struct nmb_name *ans_name, 
-               struct nmb_packet *nmb, 
-               struct response_record *n, struct subnet_record *d)
-{
-       DEBUG(4, ("Name query at %s ip %s - ",
-                 namestr(&n->name), inet_ntoa(n->send_ip)));
-
-       if (!name_equal(&n->name, ans_name))
-       {
-               /* someone gave us the wrong name as a reply. oops. */
-               /* XXXX should say to them 'oi! release that name!' */
-
-               DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
-               return;
-       }
-
-       if (nmb->header.rcode == 0 && nmb->answers->rdata)
-    {
-               /* we had sent out a name query to the current owner
-                  of a name because someone else wanted it. now they
-                  have responded saying that they still want the name,
-                  so the other host can't have it.
-                */
-
-               /* first check all the details are correct */
-
-               int nb_flags = nmb->answers->rdata[0];
-               struct in_addr found_ip;
-
-               putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
-               if (nb_flags != n->nb_flags)
-               {
-                       /* someone gave us the wrong nb_flags as a reply. oops. */
-                       /* XXXX should say to them 'oi! release that name!' */
-
-                       DEBUG(4,("expected nb_flags: %d\n", n->nb_flags));
-                       DEBUG(4,("unexpected nb_flags: %d\n", nb_flags));
-                       return;
-               }
-
-       /* do an announce host */
-       do_announce_host(ANN_HostAnnouncement,
-                               n->my_name  , 0x00, d->myip,
-                               n->name.name, 0x1d, found_ip,
-                               n->ttl,
-                               n->my_name, n->server_type, n->my_comment);
-       }
-       else
-       {
-               /* XXXX negative name query response. no master exists. oops */
-       }
-}
-
-
 /****************************************************************************
   response from a name query server check. states of type NAME_QUERY_DOM_SRV_CHK,
   NAME_QUERY_SRV_CHK, and NAME_QUERY_FIND_MST dealt with here.
   ****************************************************************************/
 static void response_server_check(struct nmb_name *ans_name, 
-               struct response_record *n, struct subnet_record *d)
+        struct response_record *n, struct subnet_record *d, struct packet_struct *p)
 {
+    struct nmb_packet *nmb = &p->packet.nmb;
+    struct in_addr send_ip;
+    enum state_type cmd;
+
+    /* This next fix was from Bernhard Laeser <nlaesb@ascom.ch>
+       who noticed we were replying directly back to the server
+       we sent to - rather than reading the response.
+     */
+
+    if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+      putip((char*)&send_ip,&nmb->answers->rdata[2]);
+    else
+      {
+      
+        DEBUG(2,("response_server_check: name query for %s failed\n", 
+              namestr(ans_name)));
+        return;
+      }
+
     /* issue another state: this time to do a name status check */
 
-    enum state_type cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
+    cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
              NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK;
 
-    /* initiate a name status check on the server that replied */
+    /* initiate a name status check on address given in the reply
+       record. In addition, the workgroup being checked has been stored
+       in the response_record->my_name (see announce_master) we
+       also propagate this into the same field. */
     queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd,
                                ans_name->name, ans_name->name_type,
-                               0,0,0,NULL,NULL,
-                               False,False,n->send_ip,n->reply_to_ip);
+                               0,0,0,n->my_name,NULL,
+                               False,False,send_ip,n->reply_to_ip, 0);
 }
 
 
@@ -211,11 +189,10 @@ static BOOL interpret_node_status(struct subnet_record *d,
                                char *p, struct nmb_name *name,int t,
                           char *serv_name, struct in_addr ip, BOOL bcast)
 {
-  int level = t==0x20 ? 4 : 0;
   int numnames = CVAL(p,0);
   BOOL found = False;
 
-  DEBUG(level,("received %d names\n",numnames));
+  DEBUG(4,("received %d names\n",numnames));
 
   p += 1;
 
@@ -246,28 +223,12 @@ static BOOL interpret_node_status(struct subnet_record *d,
       if (NAME_MFLAG    (nb_flags)) { strcat(flags,"M "); }
       if (NAME_HFLAG    (nb_flags)) { strcat(flags,"H "); }
       if (NAME_DEREG    (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
-      if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;}
+      if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); }
       if (NAME_ACTIVE   (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
       if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
-      
-      /* might as well update our namelist while we're at it */
-      if (add)
-       {
-         struct in_addr nameip;
-         enum name_source src;
-         
-         if (ismyip(ip)) {
-           nameip = ipzero;
-           src = SELF;
-         } else {
-           nameip = ip;
-           src = STATUS_QUERY;
-         }
-         add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
-       } 
 
       /* we want the server name */
-      if (serv_name && !*serv_name && !group && t == 0)
+      if (serv_name && !*serv_name && !group && type == 0x20)
        {
          StrnCpy(serv_name,qname,15);
          serv_name[15] = 0;
@@ -278,17 +239,17 @@ static BOOL interpret_node_status(struct subnet_record *d,
        {
          /* take a guess at some of the name types we're going to ask for.
             evaluate whether they are group names or no... */
-         if (((t == 0x1b || t == 0x1d             ) && !group) ||
-             ((t == 0x20 || t == 0x1c || t == 0x1e) &&  group))
+         if (((t == 0x1b || t == 0x1d || t == 0x20 ) && !group) ||
+             ((t == 0x1c || t == 0x1e              ) &&  group))
            {
              found = True;
              make_nmb_name(name,qname,type,scope);
            }
        }
       
-      DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags));
+      DEBUG(4,("\t%s(0x%x)\t%s\n",qname,type,flags));
     }
-  DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
+  DEBUG(4,("num_good_sends=%d num_good_receives=%d\n",
               IVAL(p,20),IVAL(p,24)));
   return found;
 }
@@ -308,18 +269,22 @@ static void response_name_status_check(struct in_addr ip,
        struct nmb_name name;
        fstring serv_name;
 
-       if (interpret_node_status(d,nmb->answers->rdata,
-                                 &name,name.name_type,serv_name,ip,bcast))
+       if (nmb->answers && 
+           interpret_node_status(d,nmb->answers->rdata,
+                                 &name,0x20,serv_name,ip,bcast))
        {
                if (*serv_name)
                {
+                        /* response_record->my_name contains the
+                           workgroup name to sync with. See 
+                           response_server_check() */
                        sync_server(n->state,serv_name,
-                                   name.name,name.name_type, n->send_ip);
+                                   n->my_name,name.name_type, d, n->send_ip);
                }
        }
        else
        {
-               DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
+               DEBUG(1,("No 0x20 name type in interpret_node_status()\n"));
        }
 }
 
@@ -347,7 +312,7 @@ static void response_name_query_register(struct nmb_packet *nmb,
                return;
        }
 
-       if (nmb->header.rcode == 0 && nmb->answers->rdata)
+       if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
     {
                /* we had sent out a name query to the current owner
                   of a name because someone else wanted it. now they
@@ -398,9 +363,11 @@ static void response_name_query_register(struct nmb_packet *nmb,
        }
 
        /* register the old or the new owners' ip */
-       add_name_respond(d, n->fd, d->myip, n->response_id,&n->name,n->nb_flags,
+       add_name_respond(d, n->fd, d->myip, n->reply_id,&n->name,n->nb_flags,
                                        GET_TTL(0), register_ip,
                                        new_owner, n->reply_to_ip);
+
+       remove_response_record(d,n); /* remove the response record */
 }
 
 
@@ -412,71 +379,126 @@ static void response_name_query_sync(struct nmb_packet *nmb,
                struct nmb_name *ans_name, BOOL bcast,
                struct response_record *n, struct subnet_record *d)
 {
-       DEBUG(4, ("Name query at %s ip %s - ",
-                 namestr(&n->name), inet_ntoa(n->send_ip)));
+  DEBUG(4, ("Name query at %s ip %s - ",
+           namestr(&n->name), inet_ntoa(n->send_ip)));
 
-       if (!name_equal(&n->name, ans_name))
-       {
-               /* someone gave us the wrong name as a reply. oops. */
-               DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
-               return;
-       }
-
-       if (nmb->header.rcode == 0 && nmb->answers->rdata)
+  if (!name_equal(&n->name, ans_name))
     {
-               int nb_flags = nmb->answers->rdata[0];
-               struct in_addr found_ip;
-
-               putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
-               if (!ip_equal(n->send_ip, found_ip))
-               {
-                       /* someone gave us the wrong ip as a reply. oops. */
-                       DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
-                       DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
-                       return;
-               }
-
-               DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+      /* someone gave us the wrong name as a reply. oops. */
+      DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+      return;
+    }
 
-               if (n->state == NAME_QUERY_SYNC_LOCAL ||
-                   n->state == NAME_QUERY_SYNC_REMOTE)
-               {
-                       struct work_record *work = NULL;
-                       if ((work = find_workgroupstruct(d, ans_name->name, False)))
-                       {
-                               BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL;
+  if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+    {
+      int nb_flags = nmb->answers->rdata[0];
+      struct in_addr found_ip;
+      
+      putip((char*)&found_ip,&nmb->answers->rdata[2]);
+      
+      if (!ip_equal(n->send_ip, found_ip))
+       {
+         /* someone gave us the wrong ip as a reply. oops. */
+         DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
+         DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
+         return;
+       }
 
-                               /* the server is there: sync quick before it (possibly) dies! */
-                               sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
-                                                       found_ip, local_list_only);
-                       }
-               }
-               else
-               {
-                       /* update our netbios name list (re-register it if necessary) */
-                       add_netbios_entry(d, ans_name->name, ans_name->name_type,
-                                                               nb_flags,GET_TTL(0),REGISTER,
-                                                               found_ip,False,!bcast);
-               }
+      DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+      
+      if (n->state == NAME_QUERY_SYNC_LOCAL ||
+         n->state == NAME_QUERY_SYNC_REMOTE)
+       {
+         struct work_record *work = NULL;
+         /* We cheat here as we know that the workgroup name has
+            been placed in the my_comment field of the 
+            response_record struct by the code in 
+            start_sync_browse_entry().
+         */
+         if ((work = find_workgroupstruct(d, n->my_comment, False)))
+           {
+             BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL;
+             
+             /* the server is there: sync quick before it (possibly) dies! */
+             sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
+                               found_ip, local_list_only);
+           }
        }
-       else
+      else
        {
-               DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+          struct subnet_record *add_rec = (!bcast) ? wins_client_subnet : d;
 
-               if (n->state == NAME_QUERY_CONFIRM)
-               {
-                       /* XXXX remove_netbios_entry()? */
-                       /* lots of things we ought to do, here. if we get here,
-                          then we're in a mess: our name database doesn't match
-                          reality. sort it out
+         /* update our netbios name list (re-register it if necessary) */
+         add_netbios_entry(add_rec, ans_name->name, ans_name->name_type,
+                           nb_flags,GET_TTL(0),REGISTER,
+                           found_ip,False);
+       }
+    }
+  else
+    {
+      DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+      
+      if (n->state == NAME_QUERY_CONFIRM)
+       {
+         /* XXXX remove_netbios_entry()? */
+         /* lots of things we ought to do, here. if we get here,
+            then we're in a mess: our name database doesn't match
+            reality. sort it out
              */
-               remove_netbios_name(d,n->name.name, n->name.name_type,
-                                                               REGISTER,n->send_ip);
-               }
+         remove_netbios_name(d,n->name.name, n->name.name_type, REGISTER);
        }
+    }
 }
 
+/****************************************************************************
+  response from a name query for DOMAIN<1b>
+  NAME_QUERY_DOMAIN is dealt with here - we are trying to become a domain
+  master browser and WINS replied - check it's our address.
+  ****************************************************************************/
+static void response_name_query_domain(struct nmb_name *ans_name,
+                struct nmb_packet *nmb,
+                struct response_record *n, struct subnet_record *d)
+{
+  DEBUG(4, ("response_name_query_domain: Got %s response from %s for query \
+for %s\n", nmb->header.rcode == 0 ? "success" : "failure",
+           inet_ntoa(n->send_ip), namestr(ans_name)));
+
+  /* Check the name is correct and ip address returned is our own. If it is then we
+     just remove the response record.
+   */
+  if (name_equal(&n->name, ans_name) && (nmb->header.rcode == 0) && nmb->answers && (nmb->answers->rdata))
+  {
+    struct in_addr found_ip;
+
+    putip((char*)&found_ip,&nmb->answers->rdata[2]);
+    /* Samba 1.9.16p11 servers seem to return the broadcast address for this
+       query. */
+    if (ismyip(found_ip) || ip_equal(wins_ip, found_ip) || ip_equal(ipzero, found_ip))
+    {
+      DEBUG(4, ("response_name_query_domain: WINS server returned our ip \
+address. Pretending we never received response.\n"));
+      n->num_msgs = 0;
+      n->repeat_count = 0;
+      n->repeat_time = 0;
+    }
+    else
+    {
+      DEBUG(0,("response_name_query_domain: WINS server already has a \
+domain master browser registered %s at address %s\n", 
+           namestr(ans_name), inet_ntoa(found_ip)));
+    }
+  }
+  else
+  {
+    /* Negative/incorrect response. No domain master
+       browser was registered - pretend we didn't get this response.
+     */
+    n->num_msgs = 0;
+    n->repeat_count = 0;
+    n->repeat_time = 0;
+  }
+
+}
 
 /****************************************************************************
   report the response record type
@@ -484,13 +506,13 @@ static void response_name_query_sync(struct nmb_packet *nmb,
 static void debug_rr_type(int rr_type)
 {
   switch (rr_type)
-  {
-      case NMB_STATUS: DEBUG(3,("Name status ")); break;
-         case NMB_QUERY : DEBUG(3,("Name query ")); break;
-         case NMB_REG   : DEBUG(3,("Name registration ")); break;
-         case NMB_REL   : DEBUG(3,("Name release ")); break;
-      default        : DEBUG(1,("wrong response packet type received")); break;
-  }
+    {
+    case NMB_STATUS: DEBUG(3,("Name status ")); break;
+    case NMB_QUERY : DEBUG(3,("Name query ")); break;
+    case NMB_REG   : DEBUG(3,("Name registration ")); break;
+    case NMB_REL   : DEBUG(3,("Name release ")); break;
+    default        : DEBUG(1,("wrong response packet type received")); break;
+    }
 }
 
 /****************************************************************************
@@ -500,26 +522,26 @@ void debug_state_type(int state)
 {
   /* report the state type to help debugging */
   switch (state)
-  {
-    case NAME_QUERY_DOM_SRV_CHK  : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
+    {
+    case NAME_QUERY_DOM_SRV_CHK  : DEBUG(4,("NAME_QUERY_DOM_SRV_CHK\n")); break;
     case NAME_QUERY_SRV_CHK      : DEBUG(4,("NAME_QUERY_SRV_CHK\n")); break;
     case NAME_QUERY_FIND_MST     : DEBUG(4,("NAME_QUERY_FIND_MST\n")); break;
     case NAME_QUERY_MST_CHK      : DEBUG(4,("NAME_QUERY_MST_CHK\n")); break;
     case NAME_QUERY_CONFIRM      : DEBUG(4,("NAME_QUERY_CONFIRM\n")); break;
     case NAME_QUERY_SYNC_LOCAL   : DEBUG(4,("NAME_QUERY_SYNC_LOCAL\n")); break;
     case NAME_QUERY_SYNC_REMOTE  : DEBUG(4,("NAME_QUERY_SYNC_REMOTE\n")); break;
-    case NAME_QUERY_ANNOUNCE_HOST: DEBUG(4,("NAME_QUERY_ANNCE_HOST\n"));break;
-
+    case NAME_QUERY_DOMAIN       : DEBUG(4,("NAME_QUERY_DOMAIN\n")); break;
+      
     case NAME_REGISTER           : DEBUG(4,("NAME_REGISTER\n")); break;
     case NAME_REGISTER_CHALLENGE : DEBUG(4,("NAME_REGISTER_CHALLENGE\n"));break;
-
+      
     case NAME_RELEASE            : DEBUG(4,("NAME_RELEASE\n")); break;
-
-    case NAME_STATUS_DOM_SRV_CHK : DEBUG(4,("NAME_STAT_MST_CHK\n")); break;
+      
+    case NAME_STATUS_DOM_SRV_CHK : DEBUG(4,("NAME_STATUS_DOM_SRV_CHK\n")); break;
     case NAME_STATUS_SRV_CHK     : DEBUG(4,("NAME_STATUS_SRV_CHK\n")); break;
-
+      
     default: break;
-  }
+    }
 }
 
 /****************************************************************************
@@ -528,93 +550,101 @@ void debug_state_type(int state)
   (responses for certain types of operations are only expected from one host)
   ****************************************************************************/
 static BOOL response_problem_check(struct response_record *n,
-                       struct nmb_packet *nmb, char *qname)
+                       struct nmb_packet *nmb, char *ans_name)
 {
   switch (nmb->answers->rr_type)
-  {
-    case NMB_REL:
     {
+    case NMB_REL:
+      {
         if (n->num_msgs > 1)
-        {
+         {
             DEBUG(1,("more than one release name response received!\n"));
             return True;
-        }
+         }
         break;
-    }
+      }
 
     case NMB_REG:
-    {
+      {
         if (n->num_msgs > 1)
-        {
+         {
             DEBUG(1,("more than one register name response received!\n"));
             return True;
-        }
+         }
         break;
-    }
-
+      }
+    
     case NMB_QUERY:
-    { 
-      if (n->num_msgs > 1)
-      {
-                 if (nmb->header.rcode == 0 && nmb->answers->rdata)
+      { 
+       if (n->num_msgs > 1)
+         {
+           if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+             {
+               int nb_flags = nmb->answers->rdata[0];
+               
+               if ((!NAME_GROUP(nb_flags)))
                  {
-                       int nb_flags = nmb->answers->rdata[0];
-
-                       if ((!NAME_GROUP(nb_flags)))
+                   /* oh dear. more than one person responded to a 
+                      unique name.
+                      there is either a network problem, a 
+                      configuration problem
+                      or a server is mis-behaving */
+                   
+                   /* XXXX mark the name as in conflict, and then let the
+                      person who just responded know that they 
+                      must also mark it
+                      as in conflict, and therefore must NOT use it.
+                      see rfc1001.txt 15.1.3.5 */
+                   
+                   /* this may cause problems for some 
+                      early versions of nmbd */
+                   
+                   switch (n->state)
+                     {
+                     case NAME_QUERY_FIND_MST:
                        {
-                          /* oh dear. more than one person responded to a unique name.
-                                 there is either a network problem, a configuration problem
-                                 or a server is mis-behaving */
-
-                          /* XXXX mark the name as in conflict, and then let the
-                                 person who just responded know that they must also mark it
-                                 as in conflict, and therefore must NOT use it.
-                  see rfc1001.txt 15.1.3.5 */
-                                       
-               /* this may cause problems for some early versions of nmbd */
-
-               switch (n->state)
-               {
-                case NAME_QUERY_FIND_MST:
-                {
-                  /* query for ^1^2__MSBROWSE__^2^1 expect lots of responses */
-                  return False;
-                }
-                       case NAME_QUERY_ANNOUNCE_HOST:
-                       case NAME_QUERY_DOM_SRV_CHK:
-                case NAME_QUERY_SRV_CHK:
-                case NAME_QUERY_MST_CHK:
-                {
-                     if (!strequal(qname,n->name.name))
-                     {
-                            /* one subnet, one master browser per workgroup */
-                            /* XXXX force an election? */
-
-                            DEBUG(3,("more than one master browser replied!\n"));
-                                return True;
-                         }
-                   break;
-                }
-                default: break;
-               }
-               DEBUG(3,("Unique Name conflict detected!\n"));
-                          return True;
+                         /* query for ^1^2__MSBROWSE__^2^1 expect
+                            lots of responses */
+                         return False;
                        }
+                     case NAME_QUERY_DOM_SRV_CHK:
+                     case NAME_QUERY_SRV_CHK:
+                     case NAME_QUERY_MST_CHK:
+                       {
+                         if (!strequal(ans_name,n->name.name))
+                           {
+                             /* one subnet, one master browser 
+                                per workgroup */
+                             /* XXXX force an election? */
+                             
+                             DEBUG(3,("more than one master browser replied!\n"));
+                             return True;
+                           }
+                         break;
+                       }
+                     default: break;
+                     }
+                   DEBUG(3,("Unique Name conflict detected!\n"));
+                   return True;
                  }
-                 else
-                 {
-             /* we have received a negative reply, having already received
-                at least one response (pos/neg). something's really wrong! */
-
-                DEBUG(3,("wierd name query problem detected!\n"));
-                    return True;
-                 }
-       }
+             }
+           else
+             {
+               /* we have received a negative reply, 
+                  having already received
+                  at least one response (pos/neg). 
+                  something's really wrong! */
+               
+               DEBUG(3,("wierd name query problem detected!\n"));
+               return True;
+             }
+         }
+      }
     }
-  }
   return False;
 }
 
+#if 0
 /****************************************************************************
   check that the response received is compatible with the response record
   ****************************************************************************/
@@ -625,7 +655,7 @@ static BOOL response_compatible(struct response_record *n,
   {
     case NAME_RELEASE:
     {
-               if (nmb->answers->rr_type != NMB_REL)
+               if (nmb->answers->rr_type != 0x20)
                {
                        DEBUG(1,("Name release reply has wrong answer rr_type\n"));
                        return False;
@@ -635,7 +665,7 @@ static BOOL response_compatible(struct response_record *n,
 
     case NAME_REGISTER:
     {
-               if (nmb->answers->rr_type != NMB_REG)
+               if (nmb->answers->rr_type != 0x20)
                {
                        DEBUG(1,("Name register reply has wrong answer rr_type\n"));
                        return False;
@@ -645,7 +675,6 @@ static BOOL response_compatible(struct response_record *n,
 
     case NAME_REGISTER_CHALLENGE: /* this is a query: we then do a register */
     case NAME_QUERY_CONFIRM:
-    case NAME_QUERY_ANNOUNCE_HOST:
     case NAME_QUERY_SYNC_LOCAL:
     case NAME_QUERY_SYNC_REMOTE:
     case NAME_QUERY_DOM_SRV_CHK:
@@ -653,7 +682,7 @@ static BOOL response_compatible(struct response_record *n,
     case NAME_QUERY_FIND_MST:
     case NAME_QUERY_MST_CHK:
     {
-               if (nmb->answers->rr_type != NMB_QUERY)
+               if (nmb->answers->rr_type != 0x20)
                {
                        DEBUG(1,("Name query reply has wrong answer rr_type\n"));
                        return False;
@@ -664,7 +693,7 @@ static BOOL response_compatible(struct response_record *n,
     case NAME_STATUS_DOM_SRV_CHK:
     case NAME_STATUS_SRV_CHK:
     {
-               if (nmb->answers->rr_type != NMB_STATUS)
+               if (nmb->answers->rr_type != 0x21)
                {
                        DEBUG(1,("Name status reply has wrong answer rr_type\n"));
                        return False;
@@ -680,79 +709,89 @@ static BOOL response_compatible(struct response_record *n,
   }
   return True;
 }
+#endif
 
 
 /****************************************************************************
   process the response packet received
   ****************************************************************************/
 static void response_process(struct subnet_record *d, struct packet_struct *p,
-                               struct response_record *n, struct nmb_packet *nmb,
-                               BOOL bcast, struct nmb_name *ans_name)
+                            struct response_record *n, struct nmb_packet *nmb,
+                            BOOL bcast, struct nmb_name *ans_name)
 {
   switch (n->state)
-  {
-    case NAME_RELEASE:
     {
-        response_name_release(d, p);
+    case NAME_RELEASE:
+      {
+        response_name_release(ans_name, d, p);
         break;
-    }
+      }
 
     case NAME_REGISTER:
-    {
-               response_name_reg(d, p);
+      {
+               response_name_reg(ans_name, d, p);
         break;
-    }
+      }
 
     case NAME_REGISTER_CHALLENGE:
-    {
+      {
         response_name_query_register(nmb, ans_name, n, d);
         break;
-    }
+      }
 
     case NAME_QUERY_DOM_SRV_CHK:
     case NAME_QUERY_SRV_CHK:
     case NAME_QUERY_FIND_MST:
-    {
-               response_server_check(ans_name, n, d);
-               break;
-    }
-      
+      {
+       response_server_check(ans_name, n, d, p);
+       break;
+      }
+    
     case NAME_STATUS_DOM_SRV_CHK:
     case NAME_STATUS_SRV_CHK:
-    {
-               response_name_status_check(p->ip, nmb, bcast, n, d);
-               break;
-    }
-      
-    case NAME_QUERY_ANNOUNCE_HOST:
-    {
-               response_announce_host(ans_name, nmb, n, d);
-               break;
-    }
-      
+      {
+       response_name_status_check(p->ip, nmb, bcast, n, d);
+       break;
+      }
+    
     case NAME_QUERY_CONFIRM:
     case NAME_QUERY_SYNC_LOCAL:
     case NAME_QUERY_SYNC_REMOTE:
-    {
-               response_name_query_sync(nmb, ans_name, bcast, n, d);
-               break;
-    }
+      {
+       response_name_query_sync(nmb, ans_name, bcast, n, d);
+       break;
+      }
     case NAME_QUERY_MST_CHK:
-    {
-               /* no action required here. it's when NO responses are received
-                  that we need to do something. see expire_name_query_entries() */
+      {
+       /* no action required here. it's when NO responses are received
+          that we need to do something. see expire_name_query_entries() */
        
-               DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n",
-                                       namestr(&n->name), inet_ntoa(n->send_ip)));
-               break;
-    }
-
+       DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n",
+                 namestr(&n->name), inet_ntoa(n->send_ip)));
+       break;
+      }
+   
+    case NAME_QUERY_DOMAIN:
+      {
+        /* We were asking to be a domain master browser, and someone
+           replied. If it was the WINS server and the IP it is
+           returning is our own - then remove the record and pretend
+           we didn't get a response. Else we do nothing and let 
+           dead_netbios_entry deal with it. 
+           We can only become domain master browser
+           when no broadcast responses are received and WINS
+           either contains no entry for the DOMAIN<1b> name or
+           contains our IP address.
+         */
+        response_name_query_domain(ans_name, nmb, n, d);
+        break;
+      }
     default:
-    {
-               DEBUG(1,("unknown state type received in response_netbios_packet\n"));
-               break;
+      {
+       DEBUG(1,("unknown state type received in response_netbios_packet\n"));
+       break;
+      }
     }
-  }
 }
 
 
@@ -762,61 +801,51 @@ static void response_process(struct subnet_record *d, struct packet_struct *p,
 void response_netbios_packet(struct packet_struct *p)
 {
   struct nmb_packet *nmb = &p->packet.nmb;
-  struct nmb_name *question = &nmb->question.question_name;
   struct nmb_name *ans_name = NULL;
-  char *qname = question->name;
   BOOL bcast = nmb->header.nm_flags.bcast;
   struct response_record *n;
   struct subnet_record *d = NULL;
 
   if (!(n = find_response_record(&d,nmb->header.name_trn_id))) {
-    DEBUG(2,("unknown netbios response (received late or from nmblookup?)\n"));
+    DEBUG(2,("unknown netbios response id %d (received late or from nmblookup?)\n",
+           nmb->header.name_trn_id));
     return;
   }
 
   if (!d)
-  {
-    DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
-    return;
-  }
+    {
+      DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
+      return;
+    }
 
   /* args wrong way round: spotted by ccm@shentel.net */
   if (!same_net(d->bcast_ip, p->ip, d->mask_ip)) /* copes with WINS 'subnet' */
-  {
-    DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
-    DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
-    return;
-  }
-
-  if (nmb->answers == NULL)
-  {
-      /* hm. the packet received was a response, but with no answer. wierd! */
-      DEBUG(2,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
-              inet_ntoa(p->ip), BOOLSTR(bcast)));
-      return;
+    {
+      DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
+      DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
+    }
+  
+  if (nmb->answers == NULL) {
+         /* if there is no name is the response then the name is the one
+            we queried on */
+         ans_name = &n->name;
+  } else {
+         ans_name = &nmb->answers->rr_name;
+         debug_rr_type(nmb->answers->rr_type);
   }
 
-  ans_name = &nmb->answers->rr_name;
-  DEBUG(3,("response for %s from %s (bcast=%s)\n",
-          namestr(ans_name), inet_ntoa(p->ip), BOOLSTR(bcast)));
+  DEBUG(3,("response for %s from %s(%d) (bcast=%s)\n",
+          namestr(ans_name), inet_ntoa(p->ip), p->port, BOOLSTR(bcast)));
   
-  debug_rr_type(nmb->answers->rr_type);
-
   n->num_msgs++; /* count number of responses received */
   n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
-
+  
   debug_state_type(n->state);
-
+  
   /* problem checking: multiple responses etc */
-  if (response_problem_check(n, nmb, qname))
-    return;
-
-  /* now check whether the 'state' has received the correct type of response */
-  if (!response_compatible(n, nmb))
+  if (nmb->answers && response_problem_check(n, nmb, ans_name->name))
     return;
-
+  
   /* now deal with the current state */
   response_process(d, p, n, nmb, bcast, ans_name);
 }
-
-