s3-registry: Check return code of push_reg_sz().
[kai/samba.git] / source3 / nmbd / nmbd_workgroupdb.c
index 828e29a024dda2225d6a156c445ede44b27a8736..14b33b321e1cd2262cebb346f7108f5add689893 100644 (file)
@@ -1,14 +1,13 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    NBT netbios routines and daemon - version 2
-   Copyright (C) Andrew Tridgell 1994-1997
-   Copyright (C) Luke Kenneth Casson Leighton 1994-199
-   Copyright (C) Jeremy Allison 1994-1997
+   Copyright (C) Andrew Tridgell 1994-1998
+   Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+   Copyright (C) Jeremy Allison 1994-1998
    
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
 */
 
 #include "includes.h"
-#include "smb.h"
+#include "../librpc/gen_ndr/svcctl.h"
+#include "nmbd/nmbd.h"
 
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-extern pstring myname;
-extern fstring myworkgroup;
-extern char **my_netbios_names;
 extern uint16 samba_nb_type;
-extern struct in_addr ipzero;
 
 int workgroup_count = 0; /* unique index key: one for each workgroup */
 
 /****************************************************************************
   Add a workgroup into the list.
-  **************************************************************************/
+**************************************************************************/
 
 static void add_workgroup(struct subnet_record *subrec, struct work_record *work)
 {
-  struct work_record *w2;
-
-  work->subnet = subrec;
+       work->subnet = subrec;
+       DLIST_ADD(subrec->workgrouplist, work);
+       subrec->work_changed = True;
+}
 
-  if (!subrec->workgrouplist)
-  {
-    subrec->workgrouplist = work;
-    work->prev = NULL;
-    work->next = NULL;
-    return;
-  }
-  
-  for (w2 = subrec->workgrouplist; w2->next; w2 = w2->next)
-    ;
-  
-  w2->next = work;
-  work->next = NULL;
-  work->prev = w2;
+/****************************************************************************
+ Copy name to unstring. Used by create_workgroup() and find_workgroup_on_subnet().
+**************************************************************************/
 
-  subrec->work_changed = True;
+static void name_to_unstring(unstring unname, const char *name)
+{
+        nstring nname;
+
+       errno = 0;
+       push_ascii_nstring(nname, name);
+       if (errno == E2BIG) {
+               unstring tname;
+               pull_ascii_nstring(tname, sizeof(tname), nname);
+               strlcpy(unname, tname, sizeof(nname));
+               DEBUG(0,("name_to_nstring: workgroup name %s is too long. Truncating to %s\n",
+                       name, tname));
+       } else {
+               unstrcpy(unname, name);
+       }
 }
-
+               
 /****************************************************************************
   Create an empty workgroup.
-  **************************************************************************/
+**************************************************************************/
 
-static struct work_record *create_workgroup(char *name, int ttl)
+static struct work_record *create_workgroup(const char *name, int ttl)
 {
-  struct work_record *work;
-  struct subnet_record *subrec;
-  int t = -1;
+       struct work_record *work;
+       struct subnet_record *subrec;
+       int t = -1;
   
-  if((work = (struct work_record *)malloc(sizeof(*work))) == NULL)
-  {
-    DEBUG(0,("create_workgroup: malloc fail !\n"));
-    return NULL;
-  }
-  bzero((char *)work, sizeof(*work));
-  StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
-  work->serverlist = NULL;
+       if((work = SMB_MALLOC_P(struct work_record)) == NULL) {
+               DEBUG(0,("create_workgroup: malloc fail !\n"));
+               return NULL;
+       }
+       memset((char *)work, '\0', sizeof(*work));
+
+       name_to_unstring(work->work_group, name);
+
+       work->serverlist = NULL;
   
-  work->RunningElection = False;
-  work->ElectionCount = 0;
-  work->announce_interval = 0;
-  work->needelection = False;
-  work->needannounce = True;
-  work->lastannounce_time = time(NULL);
-  work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
-  work->dom_state = DOMAIN_NONE;
-  work->log_state = LOGON_NONE;
+       work->RunningElection = False;
+       work->ElectionCount = 0;
+       work->announce_interval = 0;
+       work->needelection = False;
+       work->needannounce = True;
+       work->lastannounce_time = time(NULL);
+       work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+       work->dom_state = DOMAIN_NONE;
+       work->log_state = LOGON_NONE;
   
-  work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
+       work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
 
-  /* Make sure all token representations of workgroups are unique. */
+       /* Make sure all token representations of workgroups are unique. */
   
-  for (subrec = FIRST_SUBNET; subrec && (t == -1); 
-           subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
-  {
-    struct work_record *w;
-    for (w = subrec->workgrouplist; w && t == -1; w = w->next)
-    {
-      if (strequal(w->work_group, work->work_group))
-        t = w->token;
-    }
-  }
+       for (subrec = FIRST_SUBNET; subrec && (t == -1); subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+               struct work_record *w;
+               for (w = subrec->workgrouplist; w && t == -1; w = w->next) {
+                       if (strequal(w->work_group, work->work_group))
+                               t = w->token;
+               }
+       }
   
-  if (t == -1)
-    work->token = ++workgroup_count;
-  else
-    work->token = t;
+       if (t == -1)
+               work->token = ++workgroup_count;
+       else
+               work->token = t;
   
-  /* No known local master browser as yet. */
-  *work->local_master_browser_name = '\0';
-
-  /* No known domain master browser as yet. */
-  *work->dmb_name.name = '\0';
-  putip((char *)&work->dmb_addr, &ipzero);
-
-  /* WfWg  uses 01040b01 */
-  /* Win95 uses 01041501 */
-  /* NTAS  uses ???????? */
-  work->ElectionCriterion  = (MAINTAIN_LIST)|(ELECTION_VERSION<<8); 
-  work->ElectionCriterion |= (lp_os_level() << 24);
-  if (lp_domain_master())
-    work->ElectionCriterion |= 0x80;
+       /* No known local master browser as yet. */
+       *work->local_master_browser_name = '\0';
+
+       /* No known domain master browser as yet. */
+       *work->dmb_name.name = '\0';
+       zero_ip_v4(&work->dmb_addr);
+
+       /* WfWg  uses 01040b01 */
+       /* Win95 uses 01041501 */
+       /* NTAS  uses ???????? */
+       work->ElectionCriterion  = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8); 
+       work->ElectionCriterion |= (lp_os_level() << 24);
+       if (lp_domain_master())
+               work->ElectionCriterion |= 0x80;
   
-  return work;
+       return work;
 }
 
 /*******************************************************************
   Remove a workgroup.
-  ******************************************************************/
+******************************************************************/
 
 static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec, 
                                      struct work_record *work)
 {
-  struct work_record *ret_work = NULL;
+       struct work_record *ret_work = NULL;
   
-  DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
+       DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
   
-  ret_work = work->next;
+       ret_work = work->next;
 
-  remove_all_servers(work);
-  
-  if (!work->serverlist)
-  {
-    if (work->prev)
-      work->prev->next = work->next;
-    if (work->next)
-      work->next->prev = work->prev;
+       remove_all_servers(work);
   
-    if (subrec->workgrouplist == work)
-      subrec->workgrouplist = work->next; 
+       if (!work->serverlist) {
+               DLIST_REMOVE(subrec->workgrouplist, work);
+               ZERO_STRUCTP(work);
+               SAFE_FREE(work);
+       }
   
-    free((char *)work);
-  }
-  
-  subrec->work_changed = True;
+       subrec->work_changed = True;
 
-  return ret_work;
+       return ret_work;
 }
 
-
 /****************************************************************************
   Find a workgroup in the workgroup list of a subnet.
-  **************************************************************************/
+**************************************************************************/
 
 struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec, 
-                                             fstring name)
+                                             const char *name)
 {
-  struct work_record *ret;
-  
-  DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
-            name, subrec->subnet_name));
+       struct work_record *ret;
+       unstring un_name;
+       DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
+               name, subrec->subnet_name));
   
-  for (ret = subrec->workgrouplist; ret; ret = ret->next)
-  {
-    if (!strcmp(ret->work_group,name))
-    {
-      DEBUG(4, ("found\n"));
-      return(ret);
-    }
-  }
-  DEBUG(4, ("not found\n"));
-  return NULL;
+       name_to_unstring(un_name, name);
+
+       for (ret = subrec->workgrouplist; ret; ret = ret->next) {
+               if (strequal(ret->work_group,un_name)) {
+                       DEBUGADD(4, ("found.\n"));
+                       return(ret);
+               }
+       }
+       DEBUGADD(4, ("not found.\n"));
+       return NULL;
 }
 
 /****************************************************************************
   Create a workgroup in the workgroup list of the subnet.
-  **************************************************************************/
+**************************************************************************/
 
 struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
-                                               fstring name, int ttl)
+                                               const char *name, int ttl)
 {
-  struct work_record *work = NULL;
+       struct work_record *work = NULL;
 
-  DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
-           name, subrec->subnet_name));
+       DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
+               name, subrec->subnet_name));
   
-  if ((work = create_workgroup(name, ttl)))
-  {
-    add_workgroup(subrec, work);
-
-    subrec->work_changed = True;
+       if ((work = create_workgroup(name, ttl))) {
+               add_workgroup(subrec, work);
+               subrec->work_changed = True;
+               return(work);
+       }
 
-    return(work);
-  }
-
-  return NULL;
+       return NULL;
 }
 
 /****************************************************************************
   Update a workgroup ttl.
-  **************************************************************************/
+**************************************************************************/
 
 void update_workgroup_ttl(struct work_record *work, int ttl)
 {
-  if(work->death_time != PERMANENT_TTL)
-    work->death_time = time(NULL)+(ttl*3);
-  work->subnet->work_changed = True;
+       if(work->death_time != PERMANENT_TTL)
+               work->death_time = time(NULL)+(ttl*3);
+       work->subnet->work_changed = True;
 }
 
 /****************************************************************************
@@ -234,8 +216,8 @@ void update_workgroup_ttl(struct work_record *work, int ttl)
 static void fail_register(struct subnet_record *subrec, struct response_record *rrec,
                           struct nmb_name *nmbname)
 {  
-  DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
-            namestr(nmbname), subrec->subnet_name));
+       DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
+               nmb_namestr(nmbname), subrec->subnet_name));
 }  
 
 /****************************************************************************
@@ -244,85 +226,74 @@ static void fail_register(struct subnet_record *subrec, struct response_record *
 
 void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work)
 {
-  int i;
+       int i;
 
-  if(!strequal(myworkgroup, work->work_group))
-    return;
+       if(!strequal(lp_workgroup(), work->work_group))
+               return;
 
-  /* If this is a broadcast subnet then start elections on it
-     if we are so configured. */
+       /* If this is a broadcast subnet then start elections on it if we are so configured. */
 
-  if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
-      (subrec != wins_server_subnet) && lp_preferred_master() &&
-      lp_local_master())
-  {
-    DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
+       if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
+                       (subrec != wins_server_subnet) && lp_preferred_master() && lp_local_master()) {
+               DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
 workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
-    work->needelection = True;
-    work->ElectionCriterion |= (1<<3);
-  }  
+               work->needelection = True;
+               work->ElectionCriterion |= (1<<3);
+       }
   
-  /* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
+       /* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
 
-  register_name(subrec,myworkgroup,0x0,samba_nb_type|NB_GROUP,
-                NULL,
-                fail_register,NULL);
-     
-  register_name(subrec,myworkgroup,0x1e,samba_nb_type|NB_GROUP,
-                NULL,
-                fail_register,NULL);
-     
-  for( i = 0; my_netbios_names[i]; i++)
-  {
-    char *name = my_netbios_names[i];
-    int stype = lp_default_server_announce() | (lp_local_master() ?
-                        SV_TYPE_POTENTIAL_BROWSER : 0 );
+       register_name(subrec,lp_workgroup(),0x0,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
+       register_name(subrec,lp_workgroup(),0x1e,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
+
+       for( i = 0; my_netbios_names(i); i++) {
+               const char *name = my_netbios_names(i);
+               int stype = lp_default_server_announce() | (lp_local_master() ?  SV_TYPE_POTENTIAL_BROWSER : 0 );
    
-    if(!strequal(myname, name))
-        stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
-                   SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
+               if(!strequal(lp_netbios_name(), name))
+                       stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
    
-    create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY,
-                PERMANENT_TTL, lp_serverstring());
-    DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
+               create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY, PERMANENT_TTL, 
+                               string_truncate(lp_serverstring(talloc_tos()), MAX_SERVER_STRING_LENGTH));
+               DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
 on subnet %s\n", name, subrec->subnet_name));
-  }
+       }
 } 
 
 /****************************************************************************
   Dump a copy of the workgroup database into the log file.
   **************************************************************************/
 
-void dump_workgroups(void)
+void dump_workgroups(bool force_write)
 {
-  struct subnet_record *subrec;
-  
-  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
-  {
-    if (subrec->workgrouplist)
-    {
-      struct work_record *work;
-         
-      DEBUG(4,("dump_workgroups: dump workgroup on subnet %15s: ", subrec->subnet_name));
-      DEBUG(4,(" netmask=%15s:\n", inet_ntoa(subrec->mask_ip)));
-         
-      for (work = subrec->workgrouplist; work; work = work->next)
-      {
-        DEBUG(4,("\t%s(%d) current master browser = %s\n", work->work_group, 
-                  work->token, 
-                  *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ));
-        if (work->serverlist)
-        {
-          struct server_record *servrec;                 
-          for (servrec = work->serverlist; servrec; servrec = servrec->next)
-          {
-            DEBUG(4,("\t\t%s %8x (%s)\n",
-                  servrec->serv.name, servrec->serv.type, servrec->serv.comment));
-          }
-        }
-      }
-    }
-  }
+       struct subnet_record *subrec;
+       int debuglevel = force_write ? 0 : 4;
+       for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+               if (subrec->workgrouplist) {
+                       struct work_record *work;
+
+                       if( DEBUGLVL( debuglevel ) ) {
+                               dbgtext( "dump_workgroups()\n " );
+                               dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name );
+                               dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) );
+                       }
+
+                       for (work = subrec->workgrouplist; work; work = work->next) {
+                               DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n", work->work_group,
+                                       work->token, *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ) );
+                               if (work->serverlist) {
+                                       struct server_record *servrec;            
+                                       for (servrec = work->serverlist; servrec; servrec = servrec->next) {
+                                               DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n",
+                                                       servrec->serv.name,
+                                                       servrec->serv.type,
+                                                       servrec->serv.comment ) );
+                                       }
+                               }
+                       }
+               }
+       }
 }
 
 /****************************************************************************
@@ -332,25 +303,22 @@ void dump_workgroups(void)
 
 void expire_workgroups_and_servers(time_t t)
 {
-  struct subnet_record *subrec;
+       struct subnet_record *subrec;
    
-  for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
-  {
-    struct work_record *work;
-    struct work_record *nextwork;
-
-    for (work = subrec->workgrouplist; work; work = nextwork)
-    {
-      nextwork = work->next;
-      expire_servers(work, t);
-
-      if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) && 
-                     ((t == -1) || (work->death_time < t)))
-      {
-        DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
-                  work->work_group));
-        remove_workgroup_from_subnet(subrec, work);
-      }
-    }
-  }
+       for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
+               struct work_record *work;
+               struct work_record *nextwork;
+
+               for (work = subrec->workgrouplist; work; work = nextwork) {
+                       nextwork = work->next;
+                       expire_servers(work, t);
+
+                       if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) && 
+                                       ((t == (time_t)-1) || (work->death_time < t))) {
+                               DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
+                                               work->work_group));
+                               remove_workgroup_from_subnet(subrec, work);
+                       }
+               }
+       }
 }