LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_workgroupdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 101 126 80.2 %
Date: 2024-04-21 15:09:00 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    NBT netbios routines and daemon - version 2
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             :    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
       6             :    Copyright (C) Jeremy Allison 1994-1998
       7             :    
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             :    
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "../librpc/gen_ndr/svcctl.h"
      25             : #include "nmbd/nmbd.h"
      26             : #include "lib/util/string_wrappers.h"
      27             : 
      28             : extern uint16_t samba_nb_type;
      29             : 
      30             : int workgroup_count = 0; /* unique index key: one for each workgroup */
      31             : 
      32             : /****************************************************************************
      33             :   Add a workgroup into the list.
      34             : **************************************************************************/
      35             : 
      36          95 : static void add_workgroup(struct subnet_record *subrec, struct work_record *work)
      37             : {
      38          95 :         work->subnet = subrec;
      39          95 :         DLIST_ADD(subrec->workgrouplist, work);
      40          95 :         subrec->work_changed = True;
      41          95 : }
      42             : 
      43             : /****************************************************************************
      44             :  Copy name to unstring. Used by create_workgroup() and find_workgroup_on_subnet().
      45             : **************************************************************************/
      46             : 
      47       18732 : static void name_to_unstring(unstring unname, const char *name)
      48             : {
      49             :         nstring nname;
      50             : 
      51       18732 :         errno = 0;
      52       18732 :         push_ascii_nstring(nname, name);
      53       18732 :         if (errno == E2BIG) {
      54             :                 unstring tname;
      55           0 :                 pull_ascii_nstring(tname, sizeof(tname), nname);
      56           0 :                 strlcpy(unname, tname, sizeof(nname));
      57           0 :                 DEBUG(0,("name_to_nstring: workgroup name %s is too long. Truncating to %s\n",
      58             :                         name, tname));
      59             :         } else {
      60       18732 :                 unstrcpy(unname, name);
      61             :         }
      62       18732 : }
      63             :                 
      64             : /****************************************************************************
      65             :   Create an empty workgroup.
      66             : **************************************************************************/
      67             : 
      68          95 : static struct work_record *create_workgroup(const char *name, int ttl)
      69             : {
      70             :         struct work_record *work;
      71             :         struct subnet_record *subrec;
      72          95 :         int t = -1;
      73             :   
      74          95 :         if((work = SMB_MALLOC_P(struct work_record)) == NULL) {
      75           0 :                 DEBUG(0,("create_workgroup: malloc fail !\n"));
      76           0 :                 return NULL;
      77             :         }
      78          95 :         memset((char *)work, '\0', sizeof(*work));
      79             : 
      80          95 :         name_to_unstring(work->work_group, name);
      81             : 
      82          95 :         work->serverlist = NULL;
      83             :   
      84          95 :         work->RunningElection = False;
      85          95 :         work->ElectionCount = 0;
      86          95 :         work->announce_interval = 0;
      87          95 :         work->needelection = False;
      88          95 :         work->needannounce = True;
      89          95 :         work->lastannounce_time = time(NULL);
      90          95 :         work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
      91          95 :         work->dom_state = DOMAIN_NONE;
      92          95 :         work->log_state = LOGON_NONE;
      93             :   
      94          95 :         work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
      95             : 
      96             :         /* Make sure all token representations of workgroups are unique. */
      97             :   
      98         190 :         for (subrec = FIRST_SUBNET; subrec && (t == -1); subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
      99             :                 struct work_record *w;
     100         191 :                 for (w = subrec->workgrouplist; w && t == -1; w = w->next) {
     101          96 :                         if (strequal(w->work_group, work->work_group))
     102           0 :                                 t = w->token;
     103             :                 }
     104             :         }
     105             :   
     106          95 :         if (t == -1)
     107          95 :                 work->token = ++workgroup_count;
     108             :         else
     109           0 :                 work->token = t;
     110             :   
     111             :         /* No known local master browser as yet. */
     112          95 :         *work->local_master_browser_name = '\0';
     113             : 
     114             :         /* No known domain master browser as yet. */
     115          95 :         *work->dmb_name.name = '\0';
     116          95 :         zero_ip_v4(&work->dmb_addr);
     117             : 
     118             :         /* WfWg  uses 01040b01 */
     119             :         /* Win95 uses 01041501 */
     120             :         /* NTAS  uses ???????? */
     121          95 :         work->ElectionCriterion  = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8); 
     122          95 :         work->ElectionCriterion |= (lp_os_level() << 24);
     123          95 :         if (lp_domain_master())
     124          39 :                 work->ElectionCriterion |= 0x80;
     125             :   
     126          95 :         return work;
     127             : }
     128             : 
     129             : /*******************************************************************
     130             :   Remove a workgroup.
     131             : ******************************************************************/
     132             : 
     133           0 : static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec, 
     134             :                                      struct work_record *work)
     135             : {
     136           0 :         struct work_record *ret_work = NULL;
     137             :   
     138           0 :         DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
     139             :   
     140           0 :         ret_work = work->next;
     141             : 
     142           0 :         remove_all_servers(work);
     143             :   
     144           0 :         if (!work->serverlist) {
     145           0 :                 DLIST_REMOVE(subrec->workgrouplist, work);
     146           0 :                 ZERO_STRUCTP(work);
     147           0 :                 SAFE_FREE(work);
     148             :         }
     149             :   
     150           0 :         subrec->work_changed = True;
     151             : 
     152           0 :         return ret_work;
     153             : }
     154             : 
     155             : /****************************************************************************
     156             :   Find a workgroup in the workgroup list of a subnet.
     157             : **************************************************************************/
     158             : 
     159       18637 : struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec, 
     160             :                                              const char *name)
     161             : {
     162             :         struct work_record *ret;
     163             :         unstring un_name;
     164             :  
     165       18637 :         DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
     166             :                 name, subrec->subnet_name));
     167             :   
     168       18637 :         name_to_unstring(un_name, name);
     169             : 
     170       34425 :         for (ret = subrec->workgrouplist; ret; ret = ret->next) {
     171       34373 :                 if (strequal(ret->work_group,un_name)) {
     172       18585 :                         DEBUGADD(4, ("found.\n"));
     173       18585 :                         return(ret);
     174             :                 }
     175             :         }
     176          52 :         DEBUGADD(4, ("not found.\n"));
     177          52 :         return NULL;
     178             : }
     179             : 
     180             : /****************************************************************************
     181             :   Create a workgroup in the workgroup list of the subnet.
     182             : **************************************************************************/
     183             : 
     184          95 : struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
     185             :                                                const char *name, int ttl)
     186             : {
     187          95 :         struct work_record *work = NULL;
     188             : 
     189          95 :         DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
     190             :                 name, subrec->subnet_name));
     191             :   
     192          95 :         if ((work = create_workgroup(name, ttl))) {
     193          95 :                 add_workgroup(subrec, work);
     194          95 :                 subrec->work_changed = True;
     195          95 :                 return(work);
     196             :         }
     197             : 
     198           0 :         return NULL;
     199             : }
     200             : 
     201             : /****************************************************************************
     202             :   Update a workgroup ttl.
     203             : **************************************************************************/
     204             : 
     205         139 : void update_workgroup_ttl(struct work_record *work, int ttl)
     206             : {
     207         139 :         if(work->death_time != PERMANENT_TTL)
     208         139 :                 work->death_time = time(NULL)+(ttl*3);
     209         139 :         work->subnet->work_changed = True;
     210         139 : }
     211             : 
     212             : /****************************************************************************
     213             :  Fail function called if we cannot register the WORKGROUP<0> and
     214             :  WORKGROUP<1e> names on the net.
     215             : **************************************************************************/
     216             :      
     217           0 : static void fail_register(struct subnet_record *subrec, struct response_record *rrec,
     218             :                           struct nmb_name *nmbname)
     219             : {  
     220           0 :         DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
     221             :                 nmb_namestr(nmbname), subrec->subnet_name));
     222           0 : }  
     223             : 
     224             : /****************************************************************************
     225             :  If the workgroup is our primary workgroup, add the required names to it.
     226             : **************************************************************************/
     227             : 
     228          43 : void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work)
     229             : {
     230             :         const struct loadparm_substitution *lp_sub =
     231          43 :                 loadparm_s3_global_substitution();
     232             :         int i;
     233             : 
     234          43 :         if(!strequal(lp_workgroup(), work->work_group))
     235           0 :                 return;
     236             : 
     237             :         /* If this is a broadcast subnet then start elections on it if we are so configured. */
     238             : 
     239          43 :         if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
     240          43 :                         (subrec != wins_server_subnet) && lp_preferred_master() && lp_local_master()) {
     241          14 :                 DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
     242             : workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
     243          14 :                 work->needelection = True;
     244          14 :                 work->ElectionCriterion |= (1<<3);
     245             :         }
     246             :   
     247             :         /* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
     248             : 
     249          43 :         register_name(subrec,lp_workgroup(),0x0,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
     250          43 :         register_name(subrec,lp_workgroup(),0x1e,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
     251             : 
     252          90 :         for( i = 0; my_netbios_names(i); i++) {
     253          47 :                 const char *name = my_netbios_names(i);
     254          47 :                 int stype = lp_default_server_announce() | (lp_local_master() ?  SV_TYPE_POTENTIAL_BROWSER : 0 );
     255             :    
     256          47 :                 if(!strequal(lp_netbios_name(), name))
     257           4 :                         stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
     258             :    
     259          47 :                 create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY, PERMANENT_TTL, 
     260          47 :                                 string_truncate(lp_server_string(talloc_tos(), lp_sub), MAX_SERVER_STRING_LENGTH));
     261          47 :                 DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
     262             : on subnet %s\n", name, subrec->subnet_name));
     263             :         }
     264             : } 
     265             : 
     266             : /****************************************************************************
     267             :   Dump a copy of the workgroup database into the log file.
     268             :   **************************************************************************/
     269             : 
     270        3699 : void dump_workgroups(bool force_write)
     271             : {
     272             :         struct subnet_record *subrec;
     273        3699 :         int debuglevel = force_write ? 0 : 4;
     274             :  
     275        7398 :         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
     276        3699 :                 if (subrec->workgrouplist) {
     277             :                         struct work_record *work;
     278             : 
     279        3699 :                         if( DEBUGLVL( debuglevel ) ) {
     280          83 :                                 dbgtext( "dump_workgroups()\n " );
     281          83 :                                 dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name );
     282          83 :                                 dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) );
     283             :                         }
     284             : 
     285       12717 :                         for (work = subrec->workgrouplist; work; work = work->next) {
     286        9018 :                                 DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n", work->work_group,
     287             :                                         work->token, *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ) );
     288        9018 :                                 if (work->serverlist) {
     289             :                                         struct server_record *servrec;            
     290        9560 :                                         for (servrec = work->serverlist; servrec; servrec = servrec->next) {
     291        5861 :                                                 DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n",
     292             :                                                         servrec->serv.name,
     293             :                                                         servrec->serv.type,
     294             :                                                         servrec->serv.comment ) );
     295             :                                         }
     296             :                                 }
     297             :                         }
     298             :                 }
     299             :         }
     300        3699 : }
     301             : 
     302             : /****************************************************************************
     303             :   Expire any dead servers on all workgroups. If the workgroup has expired
     304             :   remove it.
     305             :   **************************************************************************/
     306             : 
     307        3499 : void expire_workgroups_and_servers(time_t t)
     308             : {
     309             :         struct subnet_record *subrec;
     310             :    
     311        6998 :         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
     312             :                 struct work_record *work;
     313             :                 struct work_record *nextwork;
     314             : 
     315       11969 :                 for (work = subrec->workgrouplist; work; work = nextwork) {
     316        8470 :                         nextwork = work->next;
     317        8470 :                         expire_servers(work, t);
     318             : 
     319        8470 :                         if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) && 
     320        4971 :                                         ((t == (time_t)-1) || (work->death_time < t))) {
     321           0 :                                 DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
     322             :                                                 work->work_group));
     323           0 :                                 remove_workgroup_from_subnet(subrec, work);
     324             :                         }
     325             :                 }
     326             :         }
     327        3499 : }

Generated by: LCOV version 1.14