Modified fix for bugid #784. Based on a patch from moriyama@miraclelinux.com (MORIYAM...
[samba.git] / source3 / nmbd / nmbd_become_dmb.c
index 089aa8f16a0f02a7ea796850db3220ef2343eafb..c9b0a2258071a83af38b9843586c98bdab495446 100644 (file)
@@ -1,10 +1,9 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    NBT netbios routines and daemon - version 2
    Copyright (C) Andrew Tridgell 1994-1998
    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
-   Copyright (C) Jeremy Allison 1994-1998
+   Copyright (C) Jeremy Allison 1994-2003
    
    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
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
-
-extern pstring global_myname;
-extern fstring global_myworkgroup;
-extern char **my_netbios_names;
-extern struct in_addr ipzero;
 extern struct in_addr allones_ip;
 
 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
 
-static void become_domain_master_browser_bcast(char *);
+static void become_domain_master_browser_bcast(const char *);
 
 /****************************************************************************
   Fail to become a Domain Master Browser on a subnet.
@@ -44,36 +37,37 @@ static void become_domain_master_fail(struct subnet_record *subrec,
                                       struct response_record *rrec,
                                       struct nmb_name *fail_name)
 {
-  struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
-  struct server_record *servrec;
-
-  if(!work)
-  {
-    DEBUG(0,("become_domain_master_fail: Error - cannot find \
-workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
-    return;
-  }
-
-  /* Set the state back to DOMAIN_NONE. */
-  work->dom_state = DOMAIN_NONE;
-
-  if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
-  {
-    DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
+       fstring failname;
+       struct work_record *work;
+       struct server_record *servrec;
+
+       pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
+       work = find_workgroup_on_subnet(subrec, failname);
+       if(!work) {
+               DEBUG(0,("become_domain_master_fail: Error - cannot find \
+workgroup %s on subnet %s\n", failname, subrec->subnet_name));
+               return;
+       }
+
+       /* Set the state back to DOMAIN_NONE. */
+       work->dom_state = DOMAIN_NONE;
+
+       if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
+               DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
 in workgroup %s on subnet %s\n",
-       global_myname, work->work_group, subrec->subnet_name));
-    return;
-  }
+                       global_myname(), work->work_group, subrec->subnet_name));
+               return;
+       }
 
-  /* Update our server status. */
-  servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
+       /* Update our server status. */
+       servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
 
-  /* Tell the namelist writer to write out a change. */
-  subrec->work_changed = True;
+       /* Tell the namelist writer to write out a change. */
+       subrec->work_changed = True;
 
-  DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
+       DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
 workgroup %s on subnet %s. Couldn't register name %s.\n",
-       work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
+               work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
 }
 
 /****************************************************************************
@@ -86,115 +80,112 @@ static void become_domain_master_stage2(struct subnet_record *subrec,
                                         uint16 nb_flags,
                                         int ttl, struct in_addr registered_ip)
 {
-  struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
-  struct server_record *servrec;
-
-  if(!work)
-  {
-    DEBUG(0,("become_domain_master_stage2: Error - cannot find \
-workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
-    return;
-  }
-
-  if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
-  {
-    DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
+       fstring regname;
+       struct work_record *work;
+       struct server_record *servrec;
+
+       pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
+       work = find_workgroup_on_subnet( subrec, regname);
+
+       if(!work) {
+               DEBUG(0,("become_domain_master_stage2: Error - cannot find \
+workgroup %s on subnet %s\n", regname, subrec->subnet_name));
+               return;
+       }
+
+       if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
+               DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
 in workgroup %s on subnet %s\n", 
-       global_myname, registered_name->name, subrec->subnet_name));
-    work->dom_state = DOMAIN_NONE;
-    return;
-  }
-
-  /* Set the state in the workgroup structure. */
-  work->dom_state = DOMAIN_MST; /* Become domain master. */
-
-  /* Update our server status. */
-  servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
-
-  /* Tell the namelist writer to write out a change. */
-  subrec->work_changed = True;
-
-  if( DEBUGLVL( 0 ) )
-    {
-    dbgtext( "*****\n\nSamba server %s ", global_myname );
-    dbgtext( "is now a domain master browser for " );
-    dbgtext( "workgroup %s ", work->work_group );
-    dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
-    }
-
-  if( subrec == unicast_subnet )
-  {
-    struct nmb_name nmbname;
-    struct in_addr my_first_ip;
-
-    /* Put our name and first IP address into the 
-       workgroup struct as domain master browser. This
-       will stop us syncing with ourself if we are also
-       a local master browser. */
-
-    make_nmb_name(&nmbname, global_myname, 0x20);
-
-    work->dmb_name = nmbname;
-    /* Pick the first interface ip address as the domain master browser ip. */
-    my_first_ip = *iface_n_ip(0);
-
-    putip((char *)&work->dmb_addr, &my_first_ip);
-
-    /* We successfully registered by unicast with the
-       WINS server.  We now expect to become the domain
-       master on the local subnets. If this fails, it's
-       probably a 1.9.16p2 to 1.9.16p11 server's fault.
-
-       This is a configuration issue that should be addressed
-       by the network administrator - you shouldn't have
-       several machines configured as a domain master browser
-       for the same WINS scope (except if they are 1.9.17 or
-       greater, and you know what you're doing.
-
-       see docs/DOMAIN.txt.
-
-     */
-    become_domain_master_browser_bcast(work->work_group);
-  }
-  else
-  {
-    /*
-     * Now we are a domain master on a broadcast subnet, we need to add
-     * the WORKGROUP<1b> name to the unicast subnet so that we can answer
-     * unicast requests sent to this name. This bug wasn't found for a while
-     * as it is strange to have a DMB without using WINS. JRA.
-     */
-    insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
-  }
+               global_myname(), regname, subrec->subnet_name));
+               work->dom_state = DOMAIN_NONE;
+               return;
+       }
+
+       /* Set the state in the workgroup structure. */
+       work->dom_state = DOMAIN_MST; /* Become domain master. */
+
+       /* Update our server status. */
+       servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
+
+       /* Tell the namelist writer to write out a change. */
+       subrec->work_changed = True;
+
+       if( DEBUGLVL( 0 ) ) {
+               dbgtext( "*****\n\nSamba server %s ", global_myname() );
+               dbgtext( "is now a domain master browser for " );
+               dbgtext( "workgroup %s ", work->work_group );
+               dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
+       }
+
+       if( subrec == unicast_subnet ) {
+               struct nmb_name nmbname;
+               struct in_addr my_first_ip;
+
+               /* Put our name and first IP address into the 
+                  workgroup struct as domain master browser. This
+                  will stop us syncing with ourself if we are also
+                  a local master browser. */
+
+               make_nmb_name(&nmbname, global_myname(), 0x20);
+
+               work->dmb_name = nmbname;
+               /* Pick the first interface ip address as the domain master browser ip. */
+               my_first_ip = *iface_n_ip(0);
+
+               putip((char *)&work->dmb_addr, &my_first_ip);
+
+               /* We successfully registered by unicast with the
+                  WINS server.  We now expect to become the domain
+                  master on the local subnets. If this fails, it's
+                  probably a 1.9.16p2 to 1.9.16p11 server's fault.
+
+                  This is a configuration issue that should be addressed
+                  by the network administrator - you shouldn't have
+                  several machines configured as a domain master browser
+                  for the same WINS scope (except if they are 1.9.17 or
+                  greater, and you know what you're doing.
+
+                  see docs/DOMAIN.txt.
+
+               */
+               become_domain_master_browser_bcast(work->work_group);
+       } else {
+               /*
+                * Now we are a domain master on a broadcast subnet, we need to add
+                * the WORKGROUP<1b> name to the unicast subnet so that we can answer
+                * unicast requests sent to this name. This bug wasn't found for a while
+                * as it is strange to have a DMB without using WINS. JRA.
+                */
+               insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
+       }
 }
 
 /****************************************************************************
   Start the name registration process when becoming a Domain Master Browser
   on a subnet.
-  ****************************************************************************/
+****************************************************************************/
 
-static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name)
+static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
 { 
-  struct work_record *work;
+       struct work_record *work;
 
-  DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
+       DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
 
-  /* First, find the workgroup on the subnet. */
-  if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL)
-  {
-    DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
-          wg_name, subrec->subnet_name));
-    return;
-  }
-
-  DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
-  work->dom_state = DOMAIN_WAIT;
-
-  /* WORKGROUP<1b> is the domain master browser name. */
-  register_name(subrec, work->work_group,0x1b,samba_nb_type,
-                become_domain_master_stage2,
-                become_domain_master_fail, NULL);
+       /* First, find the workgroup on the subnet. */
+       if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL) {
+               DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
+                       wg_name, subrec->subnet_name));
+               return;
+       }
+
+       DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
+       work->dom_state = DOMAIN_WAIT;
+
+       /* WORKGROUP<1b> is the domain master browser name. */
+       register_name(subrec, work->work_group,0x1b,samba_nb_type,
+                       become_domain_master_stage2,
+                       become_domain_master_fail, NULL);
 }
 
 /****************************************************************************
@@ -209,37 +200,35 @@ static void become_domain_master_query_success(struct subnet_record *subrec,
                         struct nmb_name *nmbname, struct in_addr ip, 
                         struct res_rec *rrec)
 {
-  /* If the given ip is not ours, then we can't become a domain
-     controler as the name is already registered.
-   */
-
- /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
-    address or zero ip for this query. Pretend this is ok. */
-
-  if(ismyip(ip) || ip_equal(allones_ip, ip) || ip_equal(ipzero, ip))
-  {
-    if( DEBUGLVL( 3 ) )
-    {
-      dbgtext( "become_domain_master_query_success():\n" );
-      dbgtext( "Our address (%s) ", inet_ntoa(ip) );
-      dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
-      dbgtext( "(domain master browser name) " );
-      dbgtext( "on subnet %s.\n", subrec->subnet_name );
-      dbgtext( "Continuing with domain master code.\n" );
-    }
-
-    become_domain_master_stage1(subrec, nmbname->name);
-  }
-  else
-  {
-    if( DEBUGLVL( 0 ) )
-      {
-      dbgtext( "become_domain_master_query_success:\n" );
-      dbgtext( "There is already a domain master browser at " );
-      dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), nmbname->name );
-      dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
-      }
-  }
+       fstring name;
+       pull_ascii_nstring(name, sizeof(name), nmbname->name);
+
+       /* If the given ip is not ours, then we can't become a domain
+               controler as the name is already registered.
+       */
+
+       /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
+               address or zero ip for this query. Pretend this is ok. */
+
+       if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip)) {
+               if( DEBUGLVL( 3 ) ) {
+                       dbgtext( "become_domain_master_query_success():\n" );
+                       dbgtext( "Our address (%s) ", inet_ntoa(ip) );
+                       dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
+                       dbgtext( "(domain master browser name) " );
+                       dbgtext( "on subnet %s.\n", subrec->subnet_name );
+                       dbgtext( "Continuing with domain master code.\n" );
+               }
+
+               become_domain_master_stage1(subrec, name);
+       } else {
+               if( DEBUGLVL( 0 ) ) {
+                       dbgtext( "become_domain_master_query_success:\n" );
+                       dbgtext( "There is already a domain master browser at " );
+                       dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), name );
+                       dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
+               }
+       }
 }
 
 /****************************************************************************
@@ -252,115 +241,111 @@ static void become_domain_master_query_fail(struct subnet_record *subrec,
                                     struct response_record *rrec,
                                     struct nmb_name *question_name, int fail_code)
 {
-  /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
-     then this is a failure. Otherwise, not finding the name is what we want. */
-  if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
-  {
-    DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
+       fstring name;
+
+       /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
+               then this is a failure. Otherwise, not finding the name is what we want. */
+
+       if((subrec == unicast_subnet) && (fail_code != NAM_ERR)) {
+               DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
 querying WINS server for name %s.\n", 
-                  fail_code, nmb_namestr(question_name)));
-    return;
-  }
+                       fail_code, nmb_namestr(question_name)));
+               return;
+       }
 
-  /* Otherwise - not having the name allows us to register it. */
-  become_domain_master_stage1(subrec, question_name->name);
+       /* Otherwise - not having the name allows us to register it. */
+       pull_ascii_nstring(name, sizeof(name), question_name->name);
+       become_domain_master_stage1(subrec, name);
 }
 
 /****************************************************************************
   Attempt to become a domain master browser on all broadcast subnets.
   ****************************************************************************/
 
-static void become_domain_master_browser_bcast(char *workgroup_name)
+static void become_domain_master_browser_bcast(const char *workgroup_name)
 {
-  struct subnet_record *subrec;
-
-  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
-  { 
-    struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
-
-    if (work && (work->dom_state == DOMAIN_NONE))
-    {
-      struct nmb_name nmbname;
-      make_nmb_name(&nmbname,workgroup_name,0x1b);
-
-      /*
-       * Check for our name on the given broadcast subnet first, only initiate
-       * further processing if we cannot find it.
-       */
-
-      if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
-      {
-        if( DEBUGLVL( 0 ) )
-          {
-          dbgtext( "become_domain_master_browser_bcast:\n" );
-          dbgtext( "Attempting to become domain master browser on " );
-          dbgtext( "workgroup %s on subnet %s\n",
-                    workgroup_name, subrec->subnet_name );
-          }
-
-        /* Send out a query to establish whether there's a 
-           domain controller on the local subnet. If not,
-           we can become a domain controller. 
-         */
-
-        DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
+       struct subnet_record *subrec;
+
+       for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 
+               struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
+
+               if (work && (work->dom_state == DOMAIN_NONE)) {
+                       struct nmb_name nmbname;
+                       make_nmb_name(&nmbname,workgroup_name,0x1b);
+
+                       /*
+                        * Check for our name on the given broadcast subnet first, only initiate
+                        * further processing if we cannot find it.
+                        */
+
+                       if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
+                               if( DEBUGLVL( 0 ) ) {
+                                       dbgtext( "become_domain_master_browser_bcast:\n" );
+                                       dbgtext( "Attempting to become domain master browser on " );
+                                       dbgtext( "workgroup %s on subnet %s\n",
+                                               workgroup_name, subrec->subnet_name );
+                               }
+
+                               /* Send out a query to establish whether there's a 
+                                  domain controller on the local subnet. If not,
+                                  we can become a domain controller. 
+                               */
+
+                               DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
 for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
 
-        query_name(subrec, nmbname.name, nmbname.name_type,
-                   become_domain_master_query_success, 
-                   become_domain_master_query_fail,
-                   NULL);
-      }
-    }
-  }
+                               query_name(subrec, workgroup_name, nmbname.name_type,
+                                       become_domain_master_query_success, 
+                                       become_domain_master_query_fail,
+                                       NULL);
+                       }
+               }
+       }
 }
 
 /****************************************************************************
   Attempt to become a domain master browser by registering with WINS.
   ****************************************************************************/
 
-static void become_domain_master_browser_wins(char *workgroup_name)
+static void become_domain_master_browser_wins(const char *workgroup_name)
 {
-  struct work_record *work;
+       struct work_record *work;
 
-  work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
+       work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
 
-  if (work && (work->dom_state == DOMAIN_NONE))
-  {
-    struct nmb_name nmbname;
+       if (work && (work->dom_state == DOMAIN_NONE)) {
+               struct nmb_name nmbname;
 
-    make_nmb_name(&nmbname,workgroup_name,0x1b);
+               make_nmb_name(&nmbname,workgroup_name,0x1b);
 
-    /*
-     * Check for our name on the unicast subnet first, only initiate
-     * further processing if we cannot find it.
-     */
+               /*
+                * Check for our name on the unicast subnet first, only initiate
+                * further processing if we cannot find it.
+                */
 
-    if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
-    {
-      if( DEBUGLVL( 0 ) )
-        {
-        dbgtext( "become_domain_master_browser_wins:\n" );
-        dbgtext( "Attempting to become domain master browser " );
-        dbgtext( "on workgroup %s, subnet %s.\n",
-                  workgroup_name, unicast_subnet->subnet_name );
-        }
+               if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
+                       if( DEBUGLVL( 0 ) ) {
+                               dbgtext( "become_domain_master_browser_wins:\n" );
+                               dbgtext( "Attempting to become domain master browser " );
+                               dbgtext( "on workgroup %s, subnet %s.\n",
+                                       workgroup_name, unicast_subnet->subnet_name );
+                       }
 
-      /* Send out a query to establish whether there's a 
-         domain master broswer registered with WINS. If not,
-         we can become a domain master browser. 
-       */
+                       /* Send out a query to establish whether there's a 
+                          domain master broswer registered with WINS. If not,
+                          we can become a domain master browser. 
+                       */
 
-      DEBUG(0,("become_domain_master_browser_wins: querying WINS server at IP %s \
+                       DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
 for domain master browser name %s on workgroup %s\n",
-         inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
-
-      query_name(unicast_subnet, nmbname.name, nmbname.name_type,
-                   become_domain_master_query_success,
-                   become_domain_master_query_fail,
-                   NULL);
-    }
-  }
+                               inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
+
+                       query_name(unicast_subnet, workgroup_name, nmbname.name_type,
+                               become_domain_master_query_success,
+                               become_domain_master_query_fail,
+                               NULL);
+               }
+       }
 }
 
 /****************************************************************************
@@ -370,34 +355,32 @@ for domain master browser name %s on workgroup %s\n",
 
 void add_domain_names(time_t t)
 {
-  static time_t lastrun = 0;
-
-  if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
-    return;
-
-  lastrun = t;
-
-  /* Do the "internet group" - <1c> names. */
-  if (lp_domain_logons())
-    add_logon_names();
-
-  /* Do the domain master names. */
-  if(lp_server_role() == ROLE_DOMAIN_PDC)
-  {
-    if(we_are_a_wins_client())
-    {
-      /* We register the WORKGROUP<1b> name with the WINS
-         server first, and call add_domain_master_bcast()
-         only if this is successful.
-
-         This results in domain logon services being gracefully provided,
-         as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
-         1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
-         cannot provide domain master / domain logon services.
-       */
-      become_domain_master_browser_wins(global_myworkgroup);
-    }
-    else
-      become_domain_master_browser_bcast(global_myworkgroup);
-  }
+       static time_t lastrun = 0;
+
+       if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
+               return;
+
+       lastrun = t;
+
+       /* Do the "internet group" - <1c> names. */
+       if (lp_domain_logons())
+               add_logon_names();
+
+       /* Do the domain master names. */
+       if(lp_domain_master()) {
+               if(we_are_a_wins_client()) {
+                       /* We register the WORKGROUP<1b> name with the WINS
+                               server first, and call add_domain_master_bcast()
+                               only if this is successful.
+
+                               This results in domain logon services being gracefully provided,
+                               as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
+                               1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
+                               cannot provide domain master / domain logon services.
+                       */
+                       become_domain_master_browser_wins(lp_workgroup());
+               } else {
+                       become_domain_master_browser_bcast(lp_workgroup());
+               }
+       }
 }