minor cleanups
[kai/samba.git] / source3 / nameannounce.c
index 35247b4d0b6412c9cf601fc3e70654bd280563db..4c1ef78f9ed0c36c977c8be4bad0e965ca052d05 100644 (file)
@@ -26,7 +26,6 @@
 */
 
 #include "includes.h"
-#include "loadparm.h"
 
 #define TEST_CODE
 
@@ -41,7 +40,7 @@ extern int ClientDGRAM;
 extern int ClientNMB;
 
 /* this is our domain/workgroup/server database */
-extern struct domain_record *domainlist;
+extern struct subnet_record *subnetlist;
 
 /* machine comment for host announcements */
 extern  pstring ServerComment;
@@ -49,9 +48,7 @@ extern  pstring ServerComment;
 extern int  updatecount;
 extern int  workgroup_count;
 
-/* what server type are we currently */
-
-#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+extern struct in_addr ipgrp;
 
 /****************************************************************************
   send a announce request to the local net
@@ -73,12 +70,16 @@ void announce_request(struct work_record *work, struct in_addr ip)
   CVAL(p,0) = ANN_AnnouncementRequest;
   p++;
 
-  CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
+  CVAL(p,0) = work->token; /* (local) unique workgroup token id */
   p++;
   StrnCpy(p,myname,16);
   strupper(p);
   p = skip_string(p,1);
   
+  /* XXXX note: if we sent the announcement request to 0x1d instead
+     of 0x1e, then we could get the master browser to announce to
+     us instead of the members of the workgroup. wha-hey! */
+
   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
                      myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
 }
@@ -110,8 +111,35 @@ void do_announce_request(char *info, char *to_name, int announce_type,
                      myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
 }
 
+
+/****************************************************************************
+  find a server responsible for a workgroup, and sync browse lists
+  control ends up back here via response_name_query.
+  **************************************************************************/
+void sync_server(enum state_type state, char *serv_name, char *work_name, 
+                int name_type,
+                struct in_addr ip)
+{                     
+  /* with a domain master we can get the whole list (not local only list) */
+  BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
+
+  add_browser_entry(serv_name, name_type, work_name, 0, ip, local_only);
+
+  if (state == NAME_STATUS_DOM_SRV_CHK)
+  {
+    /* announce ourselves as a master browser to serv_name */
+    do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
+                         0x20, 0, ip);
+  }
+}
+
+
 /****************************************************************************
   construct a host announcement unicast
+
+  this function should not be used heavily, and only when we are _not_
+  a master browser and _not_ a primary domain controller.
+
   **************************************************************************/
 void announce_backup(void)
 {
@@ -119,19 +147,27 @@ void announce_backup(void)
   time_t t = time(NULL);
   pstring outbuf;
   char *p;
-  struct domain_record *d1;
+  struct subnet_record *d1;
   int tok;
+  static uint32 id_count = 0;
   
   if (!lastrun) lastrun = t;
-  if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60) return;
+#if 1
+  if (t < lastrun + 1 * 60)
+#else
+  if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
+#endif
+       return;
   lastrun = t;
   
+  DEBUG(4,("checking backups...\n"));
+
   for (tok = 0; tok <= workgroup_count; tok++)
     {
-      for (d1 = domainlist; d1; d1 = d1->next)
+      for (d1 = subnetlist; d1; d1 = d1->next)
        {
          struct work_record *work;
-         struct domain_record *d;
+         struct subnet_record *d;
          
          /* search for unique workgroup: only the name matters */
          for (work = d1->workgrouplist;
@@ -140,18 +176,11 @@ void announce_backup(void)
          
          if (!work) continue;
 
+      if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
+
          /* found one: announce it across all domains */
-         for (d = domainlist; d; d = d->next)
+         for (d = subnetlist; d; d = d->next)
            {
-             int type=0;
-
-             if (AM_DOMCTL(work)) {
-               type = 0x1b;
-             } else if (AM_MASTER(work)) {
-               type = 0x1d;
-             } else {
-               continue;
-             }
              
              DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
                       inet_ntoa(d->bcast_ip),work->work_group,
@@ -159,51 +188,227 @@ void announce_backup(void)
              
              bzero(outbuf,sizeof(outbuf));
              p = outbuf;
+
              CVAL(p,0) = ANN_GetBackupListReq;
-             p++;
-             
-             CVAL(p,0) = 1; /* count? */
-             SIVAL(p,1,work->token); /* workgroup unique key index */
-             p += 5;
-             p++;
+             CVAL(p,1) = work->token; /* workgroup unique key index */
+             SIVAL(p,2,++id_count); /* unique count. not that we use it! */
+
+             p += 6;
              
-             send_mailslot_reply(BROWSE_MAILSLOT,
+          debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+             if (!AM_DOMCTL(work))
+          {
+            /* only ask for a list of backup domain controllers
+               if we are not a domain controller ourselves */
+                       
+               send_mailslot_reply(BROWSE_MAILSLOT,
                                  ClientDGRAM,outbuf,
                                  PTR_DIFF(p,outbuf),
                                  myname, work->work_group,
-                                 0x0,type,d->bcast_ip,
+                                 0x0,0x1b,d->bcast_ip,
                                  *iface_ip(d->bcast_ip));
+          }
+
+          debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+             if (!AM_MASTER(work))
+          {
+            /* only ask for a list of master browsers if we
+               are not a master browser ourselves */
+
+               send_mailslot_reply(BROWSE_MAILSLOT,
+                                 ClientDGRAM,outbuf,
+                                 PTR_DIFF(p,outbuf),
+                                 myname, work->work_group,
+                                 0x0,0x1d,d->bcast_ip,
+                                 *iface_ip(d->bcast_ip));
+          }
            }
        }
     }
 }
 
 
+/****************************************************************************
+  send a host announcement packet
+  **************************************************************************/
+void do_announce_host(int command,
+               char *from_name, int from_type, struct in_addr from_ip,
+               char *to_name  , int to_type  , struct in_addr to_ip,
+               time_t announce_interval,
+               char *server_name, int server_type, char *server_comment)
+{
+       pstring outbuf;
+       char *p;
+
+       bzero(outbuf,sizeof(outbuf));
+       p = outbuf+1;
+
+       /* command type */
+       CVAL(outbuf,0) = command;
+
+       /* announcement parameters */
+       CVAL(p,0) = updatecount;
+       SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
+
+       StrnCpy(p+5,server_name,16);
+       strupper(p+5);
+
+       CVAL(p,21) = 0x02; /* major version */
+       CVAL(p,22) = 0x02; /* minor version */
+
+       SIVAL(p,23,server_type);
+       SSVAL(p,27,0x010f); /* browse version: got from NT/AS 4.00 */
+       SSVAL(p,29,0xaa55); /* browse signature */
+
+       strcpy(p+31,server_comment);
+       p += 31;
+       p = skip_string(p,1);
+
+    debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+       /* send the announcement */
+       send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
+                                         PTR_DIFF(p,outbuf),
+                                         from_name, to_name,
+                                         from_type, to_type,
+                                         to_ip, from_ip);
+}
+
+
+/****************************************************************************
+  remove all samba's server entries
+  ****************************************************************************/
+void remove_my_servers(void)
+{
+       struct subnet_record *d; 
+       for (d = subnetlist; d; d = d->next)
+       {
+               struct work_record *work;
+               for (work = d->workgrouplist; work; work = work->next)
+               {
+                       struct server_record *s;
+                       for (s = work->serverlist; s; s = s->next)
+                       {
+                               if (!strequal(myname,s->serv.name)) continue;
+                               announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
+                       }
+               }
+       }
+}
+
+
+/****************************************************************************
+  announce a server entry
+  ****************************************************************************/
+void announce_server(struct subnet_record *d, struct work_record *work,
+                                       char *name, char *comment, time_t ttl, int server_type)
+{
+       uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX;
+       BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp);
+       
+       if (wins_iface && server_type != 0)
+       {
+               /* wins pseudo-ip interface */
+               if (!AM_MASTER(work))
+               {
+                       /* non-master announce by unicast to the domain master */
+                       if (!lp_wins_support() && *lp_wins_server())
+                       {
+                               /* look up the domain master with the WINS server */
+                               queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
+                                        NAME_QUERY_ANNOUNCE_HOST,
+                                        work->work_group,0x1b,0,ttl*1000,
+                                        server_type,name,comment,
+                                        False, False, ipzero, d->bcast_ip);
+                       }
+                       else
+                       {
+                               /* we are the WINS server, but not the domain master.  */
+                               /* XXXX we need to look up the domain master in our
+                                  WINS database list, and do_announce_host(). maybe
+                                  we could do a name query on the unsuspecting domain
+                                  master just to make sure it's awake. */
+                       }
+               }
+
+               if (AM_DOMCTL(work))
+               {
+                       /* XXXX announce to backup domain masters? */
+               }
+
+               /* XXXX any other kinds of announcements we need to consider here?
+                  e.g local master browsers... no. local master browsers do
+                  local master announcements to their domain master. they even
+                  use WINS lookup of the domain master if another wins server
+                  is being used! 
+                */
+       }
+       else
+       {
+               if (AM_MASTER(work))
+               {
+                       DEBUG(3,("sending local master announce to %s for %s(1e)\n",
+                                                       inet_ntoa(d->bcast_ip),work->work_group));
+
+                       do_announce_host(ANN_LocalMasterAnnouncement,
+                                                       name            , 0x00, d->myip,
+                                                       work->work_group, 0x1e, d->bcast_ip,
+                                                       ttl*1000,
+                                                       name, server_type, comment);
+
+                       DEBUG(3,("sending domain announce to %s for %s\n",
+                                                       inet_ntoa(d->bcast_ip),work->work_group));
+
+                       /* XXXX should we do a domain-announce-kill? */
+                       if (server_type != 0)
+                       {
+                               if (AM_DOMCTL(work))
+                               {
+                                       domain_type |= SV_TYPE_DOMAIN_CTRL;
+                               }
+                               do_announce_host(ANN_DomainAnnouncement,
+                                                       name    , 0x00, d->myip,
+                                                       MSBROWSE, 0x01, d->bcast_ip,
+                                                       ttl*1000,
+                                                       work->work_group, server_type ? domain_type : 0,
+                                                       name);
+                       }
+               }
+               else
+               {
+                       DEBUG(3,("sending host announce to %s for %s(1d)\n",
+                                                       inet_ntoa(d->bcast_ip),work->work_group));
+
+                       do_announce_host(ANN_HostAnnouncement,
+                                                       name            , 0x00, d->myip,
+                                                       work->work_group, 0x1d, d->bcast_ip,
+                                                       ttl*1000,
+                                                       name, server_type, comment);
+               }
+       }
+}
+
 /****************************************************************************
   construct a host announcement unicast
   **************************************************************************/
 void announce_host(void)
 {
   time_t t = time(NULL);
-  pstring outbuf;
-  char *p;
-  char *namep;
-  char *stypep;
-  char *commentp;
+  struct subnet_record *d;
   pstring comment;
   char *my_name;
-  struct domain_record *d;
 
   StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
 
   my_name = *myname ? myname : "NoName";
 
-  for (d = domainlist; d; d = d->next)
+  for (d = subnetlist; d; d = d->next)
     {
       struct work_record *work;
       
-      if (!ismybcast(d->bcast_ip))
-       continue;
+      if (ip_equal(d->bcast_ip, ipgrp)) continue;
 
       for (work = d->workgrouplist; work; work = work->next)
        {
@@ -211,11 +416,16 @@ void announce_host(void)
          struct server_record *s;
          BOOL announce = False;
          
+      /* must work on the code that does announcements at up to
+         30 seconds later if a master browser sends us a request
+         announce.
+       */
+
          if (work->needannounce) {
            /* drop back to a max 3 minute announce - this is to prevent a
               single lost packet from stuffing things up for too long */
-           work->announce_interval = MIN(work->announce_interval, 
-                                         CHECK_TIME_MIN_HOST_ANNCE*60);
+           work->announce_interval = MIN(work->announce_interval,
+                                               CHECK_TIME_MIN_HOST_ANNCE*60);
            work->lastannounce_time = t - (work->announce_interval+1);
          }
          
@@ -229,11 +439,13 @@ void announce_host(void)
          
          work->lastannounce_time = t;
 
-         if (!ismybcast(d->bcast_ip)) {
+         /*
+         if (!d->my_interface) {
            stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
                       SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
                       SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
          }
+         */
 
          for (s = work->serverlist; s; s = s->next) {
            if (strequal(myname, s->serv.name)) { 
@@ -243,112 +455,42 @@ void announce_host(void)
          }
          
          if (announce)
-           {
-             bzero(outbuf,sizeof(outbuf));
-             p = outbuf+1;
-             
-             CVAL(p,0) = updatecount;
-             /* ms - despite the spec */
-             SIVAL(p,1,work->announce_interval*1000); 
-             namep = p+5;
-             StrnCpy(namep,my_name,16);
-             strupper(namep);
-             CVAL(p,21) = 2; /* major version */
-             CVAL(p,22) = 2; /* minor version */
-             stypep = p+23;
-             SIVAL(p,23,stype);
-             SSVAL(p,27,0xaa55); /* browse signature */
-             SSVAL(p,29,1); /* browse version */
-             commentp = p+31;
-             strcpy(commentp,comment);
-             p = p+31;
-             p = skip_string(p,1);
-             
-             if (ismybcast(d->bcast_ip))
-               {
-                 if (AM_MASTER(work))
-                   {
-                     SIVAL(stypep,0,work->ServerType);
-                     
-                     DEBUG(2,("sending local master announce to %s for %s\n",
-                              inet_ntoa(d->bcast_ip),work->work_group));
-
-                     CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
-                     
-                     send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
-                                         PTR_DIFF(p,outbuf),
-                                         my_name,work->work_group,0,
-                                         0x1e,d->bcast_ip,
-                                         *iface_ip(d->bcast_ip));
-                     
-                     DEBUG(2,("sending domain announce to %s for %s\n",
-                              inet_ntoa(d->bcast_ip),work->work_group));
-
-                     CVAL(outbuf,0) = ANN_DomainAnnouncement;
-                     
-                     StrnCpy(namep,work->work_group,15);
-                     strupper(namep);
-                     StrnCpy(commentp,myname,15);
-                     strupper(commentp);
-                     
-                     SIVAL(stypep,0,(unsigned)0x80000000);
-                     p = commentp + strlen(commentp) + 1;
-                     
-                     send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
-                                         PTR_DIFF(p,outbuf),
-                                         my_name,MSBROWSE,0,0x01,d->bcast_ip,
-                                         *iface_ip(d->bcast_ip));
-                   }
-                 else
-                   {
-                     DEBUG(2,("sending host announce to %s for %s\n",
-                              inet_ntoa(d->bcast_ip),work->work_group));
-
-                     CVAL(outbuf,0) = ANN_HostAnnouncement;
-                     
-                     send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
-                                         PTR_DIFF(p,outbuf),
-                                         my_name,work->work_group,0,0x1d,
-                                         d->bcast_ip,*iface_ip(d->bcast_ip));
-                   }
-               }
-           }
+         {
+               announce_server(d,work,my_name,comment,work->announce_interval,stype);
+         }
          
          if (work->needannounce)
-           {
+         {
              work->needannounce = False;
              break;
              /* sorry: can't do too many announces. do some more later */
-           }
+         }
        }
-    }
+  }
 }
 
 
 /****************************************************************************
   announce myself as a master to all other primary domain conrollers.
 
-  BIG NOTE: this code will remain untested until some kind soul that has access
-  to a couple of windows NT advanced servers runs this version of nmbd for at
-  least 15 minutes.
-  
   this actually gets done in search_and_sync_workgroups() via the
-  MASTER_SERVER_CHECK command, if there is a response from the
+  NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
   name query initiated here.  see response_name_query()
   **************************************************************************/
 void announce_master(void)
 {
-  struct domain_record *d;
+  struct subnet_record *d;
   static time_t last=0;
   time_t t = time(NULL);
   BOOL am_master = False; /* are we a master of some sort? :-) */
 
-  if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60)) 
-    return; 
+  if (!last) last = t;
+  if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
+       return;
 
   last = t;
 
-  for (d = domainlist; d; d = d->next)
+  for (d = subnetlist; d; d = d->next)
     {
       struct work_record *work;
       for (work = d->workgrouplist; work; work = work->next)
@@ -362,7 +504,7 @@ void announce_master(void)
   
   if (!am_master) return; /* only proceed if we are a master browser */
   
-  for (d = domainlist; d; d = d->next)
+  for (d = subnetlist; d; d = d->next)
     {
       struct work_record *work;
       for (work = d->workgrouplist; work; work = work->next)
@@ -372,7 +514,7 @@ void announce_master(void)
            {
              if (strequal(s->serv.name, myname)) continue;
              
-             /* all PDCs (which should also be master browsers) */
+             /* all DOMs (which should also be master browsers) */
              if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
                {
                  /* check the existence of a pdc for this workgroup, and if
@@ -384,23 +526,20 @@ void announce_master(void)
                    {
                      if (!lp_wins_support() && *lp_wins_server())
                        {
-                         struct in_addr ip;
-                         ip = ipzero;
-                         
-                         queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
-                                                MASTER_SERVER_CHECK,
-                                                work->work_group,0x1b,0,
-                                                False, False, ip);
+                         queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
+                                                NAME_QUERY_DOM_SRV_CHK,
+                                                work->work_group,0x1b,0,0,0,NULL,NULL,
+                                                False, False, ipzero, ipzero);
                        }
                      else
                        {
-                         struct domain_record *d2;
-                         for (d2 = domainlist; d2; d2 = d2->next)
+                         struct subnet_record *d2;
+                         for (d2 = subnetlist; d2; d2 = d2->next)
                            {
-                             queue_netbios_packet(ClientNMB,NMB_QUERY,
-                                                  MASTER_SERVER_CHECK,
-                                                  work->work_group,0x1b,0,
-                                                  True, False, d2->bcast_ip);
+                             queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+                                                  NAME_QUERY_DOM_SRV_CHK,
+                                                  work->work_group,0x1b,0,0,0,NULL,NULL,
+                                                  True, False, d2->bcast_ip, d2->bcast_ip);
                            }
                        }
                    }
@@ -426,15 +565,15 @@ void announce_master(void)
                bcast = True;
              }
 
-             DEBUG(2, ("Searching for PDC %s at %s\n",
+             DEBUG(2, ("Searching for DOM %s at %s\n",
                        lp_domain_controller(), inet_ntoa(ip)));
              
              /* check the existence of a pdc for this workgroup, and if
                 one exists at the specified ip, sync with it and announce
                 ourselves as a master browser to it */
-             queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
-                                    work->work_group,0x1b, 0,
-                                    bcast, False, ip);
+             queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
+                                    work->work_group,0x1b,0,0,0,NULL,NULL,
+                                    bcast, False, ip, ip);
            }
        }
     }