Removed use of 'domain controller' parameter for browsing system
[kai/samba.git] / source / nameannounce.c
index ff6ee18cd12814813af8e53a4e31c11f26dc9142..b1d13ce7ac89bfbf9c727995164570d74b4b6a9e 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-1995
+   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,6 +35,7 @@ extern BOOL CanRecurse;
 extern struct in_addr ipzero;
 
 extern pstring myname;
+extern fstring myworkgroup;
 
 extern int ClientDGRAM;
 extern int ClientNMB;
@@ -42,13 +43,12 @@ extern int ClientNMB;
 /* this is our domain/workgroup/server database */
 extern struct subnet_record *subnetlist;
 
-/* machine comment for host announcements */
-extern  pstring ServerComment;
-
 extern int  updatecount;
 extern int  workgroup_count;
 
-extern struct in_addr ipgrp;
+extern struct in_addr wins_ip;
+
+extern pstring scope;
 
 /****************************************************************************
   send a announce request to the local net
@@ -80,7 +80,8 @@ void announce_request(struct work_record *work, struct in_addr ip)
      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),
+  send_mailslot_reply(False, BROWSE_MAILSLOT,ClientDGRAM,
+              outbuf,PTR_DIFF(p,outbuf),
                      myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
 }
 
@@ -107,7 +108,8 @@ void do_announce_request(char *info, char *to_name, int announce_type,
   strupper(p);
   p = skip_string(p,1);
   
-  send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+  send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
+              outbuf,PTR_DIFF(p,outbuf),
                      myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
 }
 
@@ -118,12 +120,13 @@ void do_announce_request(char *info, char *to_name, int announce_type,
   **************************************************************************/
 void sync_server(enum state_type state, char *serv_name, char *work_name, 
                 int name_type,
+                 struct subnet_record *d,
                 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;
+  BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
 
-  add_browser_entry(serv_name, name_type, work_name, 0, ip, local_only);
+  add_browser_entry(serv_name, name_type, work_name, 0, d, ip, local_only);
 
   if (state == NAME_STATUS_DOM_SRV_CHK)
   {
@@ -134,102 +137,6 @@ void sync_server(enum state_type state, char *serv_name, char *work_name,
 }
 
 
-/****************************************************************************
-  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)
-{
-  static time_t lastrun = 0;
-  time_t t = time(NULL);
-  pstring outbuf;
-  char *p;
-  struct subnet_record *d1;
-  int tok;
-  static uint32 id_count = 0;
-  
-  if (!lastrun) lastrun = t;
-#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 = subnetlist; d1; d1 = d1->next)
-       {
-         struct work_record *work;
-         struct subnet_record *d;
-         
-         /* search for unique workgroup: only the name matters */
-         for (work = d1->workgrouplist;
-              work && (tok != work->token);
-              work = work->next);
-         
-         if (!work) continue;
-
-      if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
-
-         /* found one: announce it across all domains */
-         for (d = subnetlist; d; d = d->next)
-           {
-             
-             DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
-                      inet_ntoa(d->bcast_ip),work->work_group,
-                      work->token));
-             
-             bzero(outbuf,sizeof(outbuf));
-             p = outbuf;
-
-             CVAL(p,0) = ANN_GetBackupListReq;
-             CVAL(p,1) = work->token; /* workgroup unique key index */
-             SIVAL(p,2,++id_count); /* unique count. not that we use it! */
-
-             p += 6;
-             
-          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,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
   **************************************************************************/
@@ -255,12 +162,13 @@ void do_announce_host(int command,
        StrnCpy(p+5,server_name,16);
        strupper(p+5);
 
-       CVAL(p,21) = 0x02; /* major version */
-       CVAL(p,22) = 0x02; /* minor version */
+       CVAL(p,21) = MAJOR_VERSION; /* major version */
+       CVAL(p,22) = MINOR_VERSION; /* 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 */
+       /* browse version: got from NT/AS 4.00  - Value defined in smb.h (JHT)*/
+       SSVAL(p,27,BROWSER_ELECTION_VERSION);
+       SSVAL(p,29,BROWSER_CONSTANT); /* browse signature */
 
        strcpy(p+31,server_comment);
        p += 31;
@@ -269,7 +177,7 @@ void do_announce_host(int command,
     debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
 
        /* send the announcement */
-       send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
+       send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,outbuf,
                                          PTR_DIFF(p,outbuf),
                                          from_name, to_name,
                                          from_type, to_type,
@@ -278,12 +186,12 @@ void do_announce_host(int command,
 
 
 /****************************************************************************
-  remove all samba's server entries
-  ****************************************************************************/
-void remove_my_servers(void)
+announce all samba's server entries as 'gone'.
+****************************************************************************/
+void announce_my_servers_removed(void)
 {
        struct subnet_record *d; 
-       for (d = subnetlist; d; d = d->next)
+       for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
        {
                struct work_record *work;
                for (work = d->workgrouplist; work; work = work->next)
@@ -303,21 +211,26 @@ void remove_my_servers(void)
   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)
+                    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);
+    /* domain type cannot have anything in it that might confuse
+       a client into thinking that the domain is in fact a server.
+       (SV_TYPE_SERVER_UNIX, for example)
+     */
+       uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
+       BOOL wins_iface = ip_equal(d->bcast_ip, wins_ip);
        
        if (wins_iface && server_type != 0)
        {
                /* wins pseudo-ip interface */
                if (!AM_MASTER(work))
                {
-                       /* non-master announce by unicast to the domain master */
+                       /* 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,
+                               queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
                                         NAME_QUERY_ANNOUNCE_HOST,
                                         work->work_group,0x1b,0,ttl*1000,
                                         server_type,name,comment,
@@ -325,18 +238,14 @@ void announce_server(struct subnet_record *d, struct work_record *work,
                        }
                        else
                        {
-                               /* we are the WINS server, but not the domain master.
-                                  what's going on??? and we're not going to deal with
-                                  this case, right now
-                                */
+                               /* 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
@@ -354,7 +263,7 @@ void announce_server(struct subnet_record *d, struct work_record *work,
                        do_announce_host(ANN_LocalMasterAnnouncement,
                                                        name            , 0x00, d->myip,
                                                        work->work_group, 0x1e, d->bcast_ip,
-                                                       ttl*1000,
+                                                       ttl,
                                                        name, server_type, comment);
 
                        DEBUG(3,("sending domain announce to %s for %s\n",
@@ -363,14 +272,10 @@ void announce_server(struct subnet_record *d, struct work_record *work,
                        /* 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,
+                                                       ttl,
                                                        work->work_group, server_type ? domain_type : 0,
                                                        name);
                        }
@@ -383,7 +288,7 @@ void announce_server(struct subnet_record *d, struct work_record *work,
                        do_announce_host(ANN_HostAnnouncement,
                                                        name            , 0x00, d->myip,
                                                        work->work_group, 0x1d, d->bcast_ip,
-                                                       ttl*1000,
+                                                       ttl,
                                                        name, server_type, comment);
                }
        }
@@ -392,39 +297,36 @@ void announce_server(struct subnet_record *d, struct work_record *work,
 /****************************************************************************
   construct a host announcement unicast
   **************************************************************************/
-void announce_host(void)
+void announce_host(time_t t)
 {
-  time_t t = time(NULL);
   struct subnet_record *d;
   pstring comment;
   char *my_name;
 
-  StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
+  StrnCpy(comment, lp_serverstring(), 43);
 
   my_name = *myname ? myname : "NoName";
 
-  for (d = subnetlist; d; d = d->next)
+  for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
     {
       struct work_record *work;
       
-      if (ip_equal(d->bcast_ip, ipgrp)) continue;
-
       for (work = d->workgrouplist; work; work = work->next)
        {
          uint32 stype = work->ServerType;
          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.
-       */
+         /* 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);
+                                         CHECK_TIME_MIN_HOST_ANNCE*60);
            work->lastannounce_time = t - (work->announce_interval+1);
          }
          
@@ -437,15 +339,7 @@ void announce_host(void)
            work->announce_interval += 60;
          
          work->lastannounce_time = t;
-
-         /*
-         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)) { 
              announce = True; 
@@ -453,47 +347,65 @@ void announce_host(void)
            }
          }
          
-         if (announce)
-         {
-               announce_server(d,work,my_name,comment,work->announce_interval,stype);
+         if (announce) {
+           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 timer. Moved into global static so it can be reset
+   when a machine becomes a master browser. */
+static time_t announce_timer_last=0;
 
 /****************************************************************************
-  announce myself as a master to all other primary domain conrollers.
+ Reset the announce_timer so that a master browser announce will be done
+ immediately.
+ ****************************************************************************/
+
+void reset_announce_timer()
+{
+  announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
+}
+
+/****************************************************************************
+  announce myself as a master to all other domain master browsers.
 
-  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
   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)
+void announce_master(time_t t)
 {
   struct subnet_record *d;
-  static time_t last=0;
-  time_t t = time(NULL);
+  struct work_record *work;
   BOOL am_master = False; /* are we a master of some sort? :-) */
 
-  if (!last) last = t;
-  if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
-       return;
+  if (!announce_timer_last) announce_timer_last = t;
+  if (t-announce_timer_last < CHECK_TIME_MST_ANNOUNCE * 60)
+    {
+      DEBUG(10,("announce_master: t (%d) - last(%d) < %d\n",
+                 t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 ));
+      return;
+    }
 
-  last = t;
+  if(wins_subnet == NULL)
+    {
+      DEBUG(10,("announce_master: no wins subnet, ignoring.\n"));
+      return;
+    }
 
-  for (d = subnetlist; d; d = d->next)
+  announce_timer_last = t;
+
+  for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
     {
       struct work_record *work;
       for (work = d->workgrouplist; work; work = work->next)
@@ -501,83 +413,151 @@ void announce_master(void)
          if (AM_MASTER(work))
            {
              am_master = True;
+              DEBUG(4,( "announce_master: am_master = %d for \
+workgroup %s\n", am_master, work->work_group));
            }
        }
     }
-  
   if (!am_master) return; /* only proceed if we are a master browser */
   
-  for (d = subnetlist; d; d = d->next)
+  /* Note that we don't do this if we are domain master browser
+     and that we *only* do this on the WINS subnet. */
+
+  /* Try and find our workgroup on the WINS subnet */
+  work = find_workgroupstruct(wins_subnet, myworkgroup, False);
+
+  if (work)
     {
-      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(s->serv.name, myname)) continue;
-             
-             /* 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
-                    one exists at the specified ip, sync with it and announce
-                    ourselves as a master browser to it */
-                 
-                 if (!*lp_domain_controller() ||
-                     !strequal(lp_domain_controller(), s->serv.name))
-                   {
-                     if (!lp_wins_support() && *lp_wins_server())
-                       {
-                         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 subnet_record *d2;
-                         for (d2 = subnetlist; d2; d2 = d2->next)
-                           {
-                             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);
-                           }
-                       }
-                   }
-               }
-           }
-         
-         /* now do primary domain controller - the one that's not
-            necessarily in our browse lists, although it ought to be
-            this pdc is the one that we get TOLD about through smb.conf.
-            basically, if it's on a subnet that we know about, it may end
-            up in our browse lists (which is why it's explicitly excluded
-            in the code above) */
-         
-         if (*lp_domain_controller())
-           {
-             struct in_addr ip;
-             BOOL bcast = False;
-             
-             ip = *interpret_addr2(lp_domain_controller());
-             
-             if (zero_ip(ip)) {
-               ip = d->bcast_ip;
-               bcast = True;
-             }
-
-             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(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
-                                    work->work_group,0x1b,0,0,0,NULL,NULL,
-                                    bcast, False, ip, ip);
-           }
-       }
+      char *name;
+      int   type;
+
+#if 0 /* I don't think this option should be used for this purpose. 
+         JRA.
+       */
+      if (*lp_domain_controller())
+        {
+          /* the domain controller option is used to manually specify
+             the domain master browser to sync with
+           */
+
+          /* XXXX i'm not sure we should be using the domain controller
+             option for this purpose.
+           */
+
+          name = lp_domain_controller();
+          type = 0x20;
+        }
+      else
+#endif /* REMOVE SUSPECT CODE. */
+        {
+          /* assume that the domain master browser we want to sync
+             with is our own domain.
+           */
+          name = work->work_group;
+          type = 0x1b;
+        }
+
+      /* check the existence of a dmb for this workgroup, and if
+         one exists at the specified ip, sync with it and announce
+         ourselves as a master browser to it
+       */
+
+      if (!lp_wins_support() && *lp_wins_server() )
+        {
+          DEBUG(4, ("Local Announce: find %s<%02x> from WINS server %s\n",
+                     name, type, lp_wins_server()));
+
+          queue_netbios_pkt_wins(ClientNMB,
+                    NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
+                    name, type, 0,0,0,
+                    work->work_group,NULL,
+                    False, False, ipzero, ipzero);
+        }
+      else if(lp_wins_support()) 
+        {
+           /* We are the WINS server - query ourselves for the dmb name. */
+
+           struct nmb_name netb_name;
+           struct subnet_record *d = 0;
+           struct name_record *nr = 0;
+           make_nmb_name(&netb_name, name, type, scope);
+
+           if ((nr = find_name_search(&d, &netb_name, FIND_WINS, ipzero)) == 0)
+             {
+               DEBUG(0, ("announce_master: unable to find domain master browser for workgroup %s \
+in our own WINS database.\n", work->work_group));
+               return;
+             }
+
+           /* Check that this isn't one of our addresses (ie. we are not domain master
+              ourselves) */
+           if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero))
+             {
+               DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \
+is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) ));
+               return;
+             }
+
+           /* Issue a NAME_STATUS_DOM_SRV_CHK immediately - short circuit the
+              NAME_QUERY_DOM_SRV_CHK which is done only if we are talking to a 
+              remote WINS server. */
+
+           DEBUG(4, ("announce_master: doing name status for %s<%02x> to domain master ip %s \
+for workgroup %s\n", name, type, inet_ntoa(nr->ip_flgs[0].ip), work->work_group ));
+
+           queue_netbios_packet(wins_subnet, ClientNMB,
+                    NMB_QUERY,NAME_STATUS_DOM_SRV_CHK,
+                    name, type, 0,0,0,
+                    work->work_group,NULL,
+                    False, False, nr->ip_flgs[0].ip, nr->ip_flgs[0].ip);
+         }
+
     }
 }
+
+/****************************************************************************
+  do all the "remote" announcements. These are used to put ourselves
+  on a remote browse list. They are done blind, no checking is done to
+  see if there is actually a browse master at the other end.
+  **************************************************************************/
+void announce_remote(time_t t)
+{
+  char *s,*ptr;
+  static time_t last_time = 0;
+  pstring s2;
+  struct in_addr addr;
+  char *comment,*workgroup;
+  int stype = DFLT_SERVER_TYPE;
+
+  if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
+    return;
+
+  last_time = t;
+
+  s = lp_remote_announce();
+  if (!*s) return;
+
+  comment = lp_serverstring();
+  workgroup = myworkgroup;
+
+  for (ptr=s; next_token(&ptr,s2,NULL); ) {
+    /* the entries are of the form a.b.c.d/WORKGROUP with 
+       WORKGROUP being optional */
+    char *wgroup;
+
+    wgroup = strchr(s2,'/');
+    if (wgroup) *wgroup++ = 0;
+    if (!wgroup || !*wgroup)
+      wgroup = workgroup;
+
+    addr = *interpret_addr2(s2);
+    
+    do_announce_host(ANN_HostAnnouncement,myname,0x20,*iface_ip(addr),
+                    wgroup,0x1e,addr,
+                    REMOTE_ANNOUNCE_INTERVAL,
+                    myname,stype,comment);    
+  }
+
+}