LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_incomingdgrams.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 92 257 35.8 %
Date: 2024-04-21 15:09:00 Functions: 4 10 40.0 %

          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 bool found_lm_clients;
      29             : 
      30             : #if 0
      31             : 
      32             : /* XXXX note: This function is currently unsuitable for use, as it
      33             :    does not properly check that a server is in a fit state to become
      34             :    a backup browser before asking it to be one.
      35             :    The code is left here to be worked on at a later date.
      36             : */
      37             : 
      38             : /****************************************************************************
      39             : Tell a server to become a backup browser
      40             : **************************************************************************/
      41             : 
      42             : void tell_become_backup(void)
      43             : {
      44             :   struct subnet_record *subrec;
      45             :   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
      46             :   {
      47             :     struct work_record *work;
      48             :     for (work = subrec->workgrouplist; work; work = work->next)
      49             :     {
      50             :       struct server_record *servrec;
      51             :       int num_servers = 0;
      52             :       int num_backups = 0;
      53             : 
      54             :       for (servrec = work->serverlist; servrec; servrec = servrec->next)
      55             :       {
      56             :         num_servers++;
      57             : 
      58             :         if (is_myname(servrec->serv.name))
      59             :           continue;
      60             : 
      61             :         if (servrec->serv.type & SV_TYPE_BACKUP_BROWSER)
      62             :         {
      63             :           num_backups++;
      64             :           continue;
      65             :         }
      66             : 
      67             :         if (servrec->serv.type & SV_TYPE_MASTER_BROWSER)
      68             :           continue;
      69             : 
      70             :         if (!(servrec->serv.type & SV_TYPE_POTENTIAL_BROWSER))
      71             :           continue;
      72             : 
      73             :         DEBUG(3,("num servers: %d num backups: %d\n",
      74             :               num_servers, num_backups));
      75             : 
      76             :         /* make first server a backup server. thereafter make every
      77             :            tenth server a backup server */
      78             :         if (num_backups != 0 && (num_servers+9) / num_backups > 10)
      79             :           continue;
      80             : 
      81             :         DEBUG(2,("sending become backup to %s %s for %s\n",
      82             :              servrec->serv.name, inet_ntoa(subrec->bcast_ip),
      83             :              work->work_group));
      84             : 
      85             :         /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
      86             :         do_announce_request(servrec->serv.name, work->work_group,
      87             :               ANN_BecomeBackup, 0x20, 0x1e, subrec->bcast_ip);
      88             :       }
      89             :     }
      90             :   }
      91             : }
      92             : #endif
      93             : 
      94             : /*******************************************************************
      95             :   Process an incoming host announcement packet.
      96             : *******************************************************************/
      97             : 
      98          58 : void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, const char *buf)
      99             : {
     100          58 :         struct dgram_packet *dgram = &p->packet.dgram;
     101          58 :         int ttl = IVAL(buf,1)/1000;
     102             :         unstring announce_name;
     103          58 :         uint32_t servertype = IVAL(buf,23);
     104             :         fstring comment;
     105             :         struct work_record *work;
     106             :         struct server_record *servrec;
     107             :         unstring work_name;
     108             :         unstring source_name;
     109          58 :         ZERO_STRUCT(source_name);
     110          58 :         ZERO_STRUCT(announce_name);
     111             : 
     112          58 :         pull_ascii_fstring(comment, buf+31);
     113             : 
     114          58 :         pull_ascii_nstring(announce_name, sizeof(announce_name), buf+5);
     115          58 :         pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
     116             : 
     117          58 :         DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \
     118             : %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
     119             :                         nmb_namestr(&dgram->dest_name),announce_name));
     120             : 
     121          58 :         DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n",
     122             :                 ttl, servertype,comment));
     123             : 
     124             :         /* Filter servertype to remove impossible bits. */
     125          58 :         servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
     126             : 
     127             :         /* A host announcement must be sent to the name WORKGROUP<1d>. */
     128          58 :         if(dgram->dest_name.name_type != 0x1d) {
     129           0 :                 DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \
     130             : (was %02x) should be 0x1d. Allowing packet anyway.\n",
     131             :                         inet_ntoa(p->ip), dgram->dest_name.name_type));
     132             :                 /* Change it so it was. */
     133           0 :                 dgram->dest_name.name_type = 0x1d;
     134             :         }
     135             : 
     136             :         /* For a host announce the workgroup name is the destination name. */
     137          58 :         pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name);
     138             : 
     139             :         /*
     140             :          * Syntax servers version 5.1 send HostAnnounce packets to
     141             :          * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
     142             :          * instead of WORKGROUP<1d> name. So to fix this we check if
     143             :          * the workgroup name is our own name, and if so change it
     144             :          * to be our primary workgroup name.
     145             :          */
     146             : 
     147          58 :         if(strequal(work_name, lp_netbios_name()))
     148           0 :                 unstrcpy(work_name,lp_workgroup());
     149             : 
     150             :         /*
     151             :          * We are being very aggressive here in adding a workgroup
     152             :          * name on the basis of a host announcing itself as being
     153             :          * in that workgroup. Maybe we should wait for the workgroup
     154             :          * announce instead ? JRA.
     155             :          */
     156             : 
     157          58 :         work = find_workgroup_on_subnet(subrec, work_name);
     158             : 
     159          58 :         if(servertype != 0) {
     160          51 :                 if (work ==NULL ) {
     161             :                         /* We have no record of this workgroup. Add it. */
     162           0 :                         if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
     163           0 :                                 goto done;
     164             :                 }
     165             : 
     166          51 :                 if((servrec = find_server_in_workgroup( work, announce_name))==NULL) {
     167             :                         /* If this server is not already in the workgroup, add it. */
     168          16 :                         create_server_on_workgroup(work, announce_name,
     169          16 :                                 servertype|SV_TYPE_LOCAL_LIST_ONLY,
     170             :                                 ttl, comment);
     171             :                 } else {
     172             :                         /* Update the record. */
     173          35 :                         servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
     174          35 :                         update_server_ttl( servrec, ttl);
     175          35 :                         strlcpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment));
     176             :                 }
     177             :         } else {
     178             :                 /*
     179             :                  * This server is announcing it is going down. Remove it from the
     180             :                  * workgroup.
     181             :                  */
     182          14 :                 if(!is_myname(announce_name) && (work != NULL) &&
     183           7 :                                 ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) {
     184           7 :                         remove_server_from_workgroup( work, servrec);
     185             :                 }
     186             :         }
     187             : 
     188          58 :         subrec->work_changed = True;
     189          58 : done:
     190          58 :         return;
     191             : }
     192             : 
     193             : /*******************************************************************
     194             :   Process an incoming WORKGROUP announcement packet.
     195             : *******************************************************************/
     196             : 
     197         191 : void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, const char *buf)
     198             : {
     199         191 :         struct dgram_packet *dgram = &p->packet.dgram;
     200         191 :         int ttl = IVAL(buf,1)/1000;
     201             :         unstring workgroup_announce_name;
     202             :         unstring master_name;
     203         191 :         uint32_t servertype = IVAL(buf,23);
     204             :         struct work_record *work;
     205             :         unstring source_name;
     206             :         unstring dest_name;
     207             : 
     208         191 :         pull_ascii_nstring(workgroup_announce_name,sizeof(workgroup_announce_name),buf+5);
     209         191 :         pull_ascii_nstring(master_name,sizeof(master_name),buf+31);
     210         191 :         pull_ascii_nstring(source_name,sizeof(source_name),dgram->source_name.name);
     211         191 :         pull_ascii_nstring(dest_name,sizeof(dest_name),dgram->dest_name.name);
     212             : 
     213         191 :         DEBUG(3,("process_workgroup_announce: from %s<%02x> IP %s to \
     214             : %s for workgroup %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
     215             :                         nmb_namestr(&dgram->dest_name),workgroup_announce_name));
     216             : 
     217         191 :         DEBUG(5,("process_workgroup_announce: ttl=%d server type=%08x master browser=%s\n",
     218             :                 ttl, servertype, master_name));
     219             : 
     220             :         /* Workgroup announcements must only go to the MSBROWSE name. */
     221         191 :         if (!strequal(dest_name, MSBROWSE) || (dgram->dest_name.name_type != 0x1)) {
     222           0 :                 DEBUG(0,("process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s\n",
     223             :                         inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
     224           0 :                 goto done;
     225             :         }
     226             : 
     227         191 :         if ((work = find_workgroup_on_subnet(subrec, workgroup_announce_name))==NULL) {
     228             :                 /* We have no record of this workgroup. Add it. */
     229          52 :                 if((work = create_workgroup_on_subnet(subrec, workgroup_announce_name, ttl))==NULL)
     230           0 :                         goto done;
     231             :         } else {
     232             :                 /* Update the workgroup death_time. */
     233         139 :                 update_workgroup_ttl(work, ttl);
     234             :         }
     235             : 
     236         191 :         if(*work->local_master_browser_name == '\0') {
     237             :                 /* Set the master browser name. */
     238          52 :                 set_workgroup_local_master_browser_name( work, master_name );
     239             :         }
     240             : 
     241         191 :         subrec->work_changed = True;
     242             : 
     243         191 : done:
     244         191 :         return;
     245             : }
     246             : 
     247             : /*******************************************************************
     248             :   Process an incoming local master browser announcement packet.
     249             : *******************************************************************/
     250             : 
     251          47 : void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, const char *buf)
     252             : {
     253          47 :         struct dgram_packet *dgram = &p->packet.dgram;
     254          47 :         int ttl = IVAL(buf,1)/1000;
     255             :         unstring server_name;
     256          47 :         uint32_t servertype = IVAL(buf,23);
     257             :         fstring comment;
     258             :         unstring work_name;
     259          47 :         struct work_record *work = NULL;
     260             :         struct server_record *servrec;
     261             :         unstring source_name;
     262             : 
     263          47 :         pull_ascii_nstring(server_name,sizeof(server_name),buf+5);
     264          47 :         pull_ascii_fstring(comment, buf+31);
     265          47 :         pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
     266          47 :         pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name);
     267             : 
     268          47 :         DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \
     269             : %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
     270             :                 nmb_namestr(&dgram->dest_name),server_name));
     271             : 
     272          47 :         DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n",
     273             :                 ttl, servertype, comment));
     274             : 
     275             :         /* A local master announcement must be sent to the name WORKGROUP<1e>. */
     276          47 :         if(dgram->dest_name.name_type != 0x1e) {
     277           0 :                 DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \
     278             : (was %02x) should be 0x1e. Ignoring packet.\n",
     279             :                         inet_ntoa(p->ip), dgram->dest_name.name_type));
     280           0 :                 goto done;
     281             :         }
     282             : 
     283             :         /* Filter servertype to remove impossible bits. */
     284          47 :         servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
     285             : 
     286             :         /* For a local master announce the workgroup name is the destination name. */
     287             : 
     288          47 :         if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL) {
     289             :                 /* Don't bother adding if it's a local master release announce. */
     290           0 :                 if(servertype == 0)
     291           0 :                         goto done;
     292             : 
     293             :                 /* We have no record of this workgroup. Add it. */
     294           0 :                 if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
     295           0 :                         goto done;
     296             :         }
     297             : 
     298             :         /* If we think we're the local master browser for this workgroup,
     299             :                 we should never have got this packet. We don't see our own
     300             :                 packets.
     301             :         */
     302          47 :         if(AM_LOCAL_MASTER_BROWSER(work)) {
     303           0 :                 DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \
     304             : a local master browser for workgroup %s and we think we are master. Forcing election.\n",
     305             :                         server_name, inet_ntoa(p->ip), work_name));
     306             : 
     307             :                 /* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
     308             :                  they have become a local master browser once, they will never
     309             :                  stop sending local master announcements. To fix this we send
     310             :                  them a reset browser packet, with level 0x2 on the __SAMBA__
     311             :                  name that only they should be listening to. */
     312             : 
     313           0 :                 send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip);
     314             : 
     315             :                 /* We should demote ourself and force an election. */
     316             : 
     317           0 :                 unbecome_local_master_browser( subrec, work, True);
     318             : 
     319             :                 /* The actual election requests are handled in nmbd_election.c */
     320           0 :                 goto done;
     321             :         }
     322             : 
     323             :         /* Find the server record on this workgroup. If it doesn't exist, add it. */
     324             : 
     325          47 :         if(servertype != 0) {
     326          40 :                 if((servrec = find_server_in_workgroup( work, server_name))==NULL) {
     327             :                         /* If this server is not already in the workgroup, add it. */
     328          14 :                         create_server_on_workgroup(work, server_name,
     329          14 :                                 servertype|SV_TYPE_LOCAL_LIST_ONLY,
     330             :                                 ttl, comment);
     331             :                 } else {
     332             :                         /* Update the record. */
     333          26 :                         if (servrec->serv.type !=
     334          26 :                                         (servertype|SV_TYPE_LOCAL_LIST_ONLY)) {
     335           1 :                                 servrec->serv.type =
     336           1 :                                         servertype|SV_TYPE_LOCAL_LIST_ONLY;
     337           1 :                                 subrec->work_changed = true;
     338             :                         }
     339          26 :                         if (!strequal(servrec->serv.comment,comment)) {
     340           0 :                                 strlcpy(servrec->serv.comment,
     341             :                                         comment,
     342             :                                         sizeof(servrec->serv.comment));
     343           0 :                                 subrec->work_changed = true;
     344             :                         }
     345          26 :                         update_server_ttl(servrec, ttl);
     346             :                 }
     347             : 
     348          40 :                 if (!strequal(work->local_master_browser_name, server_name)) {
     349          15 :                         set_workgroup_local_master_browser_name( work, server_name );
     350          15 :                         subrec->work_changed = true;
     351             :                 }
     352             :         } else {
     353             :                 /*
     354             :                  * This server is announcing it is going down. Remove it from the
     355             :                  * workgroup.
     356             :                  */
     357          14 :                 if(!is_myname(server_name) &&
     358           7 :                                 ((servrec = find_server_in_workgroup( work, server_name))!=NULL)) {
     359           5 :                         remove_server_from_workgroup( work, servrec);
     360             :                 }
     361             :         }
     362             : 
     363           2 : done:
     364          47 :         return;
     365             : }
     366             : 
     367             : /*******************************************************************
     368             :   Process a domain master announcement frame.
     369             :   Domain master browsers receive these from local masters. The Domain
     370             :   master should then issue a sync with the local master, asking for
     371             :   that machines local server list.
     372             : ******************************************************************/
     373             : 
     374           0 : void process_master_browser_announce(struct subnet_record *subrec,
     375             :                                      struct packet_struct *p,const char *buf)
     376             : {
     377             :         unstring local_master_name;
     378             :         struct work_record *work;
     379             :         struct browse_cache_record *browrec;
     380             : 
     381           0 :         pull_ascii_nstring(local_master_name,sizeof(local_master_name),buf);
     382             : 
     383           0 :         DEBUG(3,("process_master_browser_announce: Local master announce from %s IP %s.\n",
     384             :                 local_master_name, inet_ntoa(p->ip)));
     385             : 
     386           0 :         if (!lp_domain_master()) {
     387           0 :                 DEBUG(0,("process_master_browser_announce: Not configured as domain \
     388             : master - ignoring master announce.\n"));
     389           0 :                 goto done;
     390             :         }
     391             : 
     392           0 :         if((work = find_workgroup_on_subnet(subrec, lp_workgroup())) == NULL) {
     393           0 :                 DEBUG(0,("process_master_browser_announce: Cannot find workgroup %s on subnet %s\n",
     394             :                         lp_workgroup(), subrec->subnet_name));
     395           0 :                 goto done;
     396             :         }
     397             : 
     398           0 :         if(!AM_DOMAIN_MASTER_BROWSER(work)) {
     399           0 :                 DEBUG(0,("process_master_browser_announce: Local master announce made to us from \
     400             : %s IP %s and we are not a domain master browser.\n", local_master_name, inet_ntoa(p->ip)));
     401           0 :                 goto done;
     402             :         }
     403             : 
     404             :         /* Add this host as a local master browser entry on the browse lists.
     405             :                 This causes a sync request to be made to it at a later date.
     406             :         */
     407             : 
     408           0 :         if((browrec = find_browser_in_lmb_cache( local_master_name )) == NULL) {
     409             :                 /* Add it. */
     410           0 :                 create_browser_in_lmb_cache( work->work_group, local_master_name, p->ip);
     411             :         } else {
     412           0 :                 update_browser_death_time(browrec);
     413             :         }
     414             : 
     415           0 : done:
     416           0 :         return;
     417             : }
     418             : 
     419             : /*******************************************************************
     420             :   Process an incoming LanMan host announcement packet.
     421             : *******************************************************************/
     422             : 
     423           0 : void process_lm_host_announce(struct subnet_record *subrec, struct packet_struct *p, const char *buf, int len)
     424             : {
     425           0 :         struct dgram_packet *dgram = &p->packet.dgram;
     426           0 :         uint32_t servertype = IVAL(buf,1);
     427           0 :         int osmajor=CVAL(buf,5);           /* major version of node software */
     428           0 :         int osminor=CVAL(buf,6);           /* minor version of node software */
     429           0 :         int ttl = SVAL(buf,7);
     430             :         unstring announce_name;
     431             :         struct work_record *work;
     432             :         struct server_record *servrec;
     433             :         unstring work_name;
     434             :         unstring source_name;
     435             :         fstring comment;
     436           0 :         char *s = get_safe_str_ptr(buf,len,discard_const_p(char, buf),9);
     437             : 
     438           0 :         if (!s) {
     439           0 :                 goto done;
     440             :         }
     441           0 :         s = skip_string(buf,len,s);
     442           0 :         if (!s) {
     443           0 :                 goto done;
     444             :         }
     445           0 :         pull_ascii(comment, s, sizeof(fstring), 43, STR_TERMINATE);
     446             : 
     447           0 :         pull_ascii_nstring(announce_name,sizeof(announce_name),buf+9);
     448           0 :         pull_ascii_nstring(source_name,sizeof(source_name),dgram->source_name.name);
     449             :         /* For a LanMan host announce the workgroup name is the destination name. */
     450           0 :         pull_ascii_nstring(work_name,sizeof(work_name),dgram->dest_name.name);
     451             : 
     452           0 :         DEBUG(3,("process_lm_host_announce: LM Announcement from %s IP %s to \
     453             : %s for server %s.\n", nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
     454             :                 nmb_namestr(&dgram->dest_name),announce_name));
     455             : 
     456           0 :         DEBUG(5,("process_lm_host_announce: os=(%d,%d) ttl=%d server type=%08x comment=%s\n",
     457             :                 osmajor, osminor, ttl, servertype,comment));
     458             : 
     459           0 :         if ((osmajor < 36) || (osmajor > 38) || (osminor !=0)) {
     460           0 :                 DEBUG(5,("process_lm_host_announce: LM Announcement packet does not \
     461             : originate from OS/2 Warp client. Ignoring packet.\n"));
     462             :                 /* Could have been from a Windows machine (with its LM Announce enabled),
     463             :                         or a Samba server. Then don't disrupt the current browse list. */
     464           0 :                 goto done;
     465             :         }
     466             : 
     467             :         /* Filter servertype to remove impossible bits. */
     468           0 :         servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
     469             : 
     470             :         /* A LanMan host announcement must be sent to the name WORKGROUP<00>. */
     471           0 :         if(dgram->dest_name.name_type != 0x00) {
     472           0 :                 DEBUG(2,("process_lm_host_announce: incorrect name type for destination from IP %s \
     473             : (was %02x) should be 0x00. Allowing packet anyway.\n",
     474             :                         inet_ntoa(p->ip), dgram->dest_name.name_type));
     475             :                 /* Change it so it was. */
     476           0 :                 dgram->dest_name.name_type = 0x00;
     477             :         }
     478             : 
     479             :         /*
     480             :          * Syntax servers version 5.1 send HostAnnounce packets to
     481             :          * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
     482             :          * instead of WORKGROUP<1d> name. So to fix this we check if
     483             :          * the workgroup name is our own name, and if so change it
     484             :          * to be our primary workgroup name. This code is probably
     485             :          * not needed in the LanMan announce code, but it won't hurt.
     486             :          */
     487             : 
     488           0 :         if(strequal(work_name, lp_netbios_name()))
     489           0 :                 unstrcpy(work_name,lp_workgroup());
     490             : 
     491             :         /*
     492             :          * We are being very aggressive here in adding a workgroup
     493             :          * name on the basis of a host announcing itself as being
     494             :          * in that workgroup. Maybe we should wait for the workgroup
     495             :          * announce instead ? JRA.
     496             :          */
     497             : 
     498           0 :         work = find_workgroup_on_subnet(subrec, work_name);
     499             : 
     500           0 :         if(servertype != 0) {
     501           0 :                 if (work == NULL) {
     502             :                         /* We have no record of this workgroup. Add it. */
     503           0 :                         if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
     504           0 :                                 goto done;
     505             :                 }
     506             : 
     507           0 :                 if((servrec = find_server_in_workgroup( work, announce_name))==NULL) {
     508             :                         /* If this server is not already in the workgroup, add it. */
     509           0 :                         create_server_on_workgroup(work, announce_name,
     510           0 :                                         servertype|SV_TYPE_LOCAL_LIST_ONLY,
     511             :                                         ttl, comment);
     512             :                 } else {
     513             :                         /* Update the record. */
     514           0 :                         servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
     515           0 :                         update_server_ttl( servrec, ttl);
     516           0 :                         strlcpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment));
     517             :                 }
     518             :         } else {
     519             :                 /*
     520             :                  * This server is announcing it is going down. Remove it from the
     521             :                  * workgroup.
     522             :                  */
     523           0 :                 if(!is_myname(announce_name) && (work != NULL) &&
     524           0 :                                 ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) {
     525           0 :                         remove_server_from_workgroup( work, servrec);
     526             :                 }
     527             :         }
     528             : 
     529           0 :         subrec->work_changed = True;
     530           0 :         found_lm_clients = True;
     531             : 
     532           0 : done:
     533           0 :         return;
     534             : }
     535             : 
     536             : /****************************************************************************
     537             :   Send a backup list response.
     538             : *****************************************************************************/
     539             : 
     540           0 : static void send_backup_list_response(struct subnet_record *subrec,
     541             :                                       struct work_record *work,
     542             :                                       struct nmb_name *send_to_name,
     543             :                                       unsigned char max_number_requested,
     544             :                                       uint32_t token, struct in_addr sendto_ip,
     545             :                                       int port)
     546             : {
     547             :         char outbuf[1024];
     548             :         char *p, *countptr;
     549           0 :         unsigned int count = 0;
     550             :         unstring send_to_namestr;
     551             : #if 0
     552             :   struct server_record *servrec;
     553             : #endif
     554             :         unstring myname;
     555             : 
     556           0 :         memset(outbuf,'\0',sizeof(outbuf));
     557             : 
     558           0 :         DEBUG(3,("send_backup_list_response: sending backup list for workgroup %s to %s IP %s\n",
     559             :                 work->work_group, nmb_namestr(send_to_name), inet_ntoa(sendto_ip)));
     560             : 
     561           0 :         p = outbuf;
     562             : 
     563           0 :         SCVAL(p,0,ANN_GetBackupListResp); /* Backup list response opcode. */
     564           0 :         p++;
     565             : 
     566           0 :         countptr = p;
     567           0 :         p++;
     568             : 
     569           0 :         SIVAL(p,0,token); /* The sender's unique info. */
     570           0 :         p += 4;
     571             : 
     572             :         /* We always return at least one name - our own. */
     573           0 :         count = 1;
     574           0 :         unstrcpy(myname, lp_netbios_name());
     575           0 :         if (!strupper_m(myname)) {
     576           0 :                 DEBUG(4,("strupper_m %s failed\n", myname));
     577           0 :                 return;
     578             :         }
     579           0 :         myname[15]='\0';
     580           0 :         push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
     581             : 
     582           0 :         p = skip_string(outbuf,sizeof(outbuf),p);
     583             : 
     584             :         /* Look for backup browsers in this workgroup. */
     585             : 
     586             : #if 0
     587             :   /* we don't currently send become_backup requests so we should never
     588             :      send any other servers names out as backups for our
     589             :      workgroup. That's why this is commented out (tridge) */
     590             : 
     591             :   /*
     592             :    * NB. Note that the struct work_record here is not necessarily
     593             :    * attached to the subnet *subrec.
     594             :    */
     595             : 
     596             :   for (servrec = work->serverlist; servrec; servrec = servrec->next)
     597             :   {
     598             :     int len = PTR_DIFF(p, outbuf);
     599             :     if((sizeof(outbuf) - len) < 16)
     600             :       break;
     601             : 
     602             :     if(count >= (unsigned int)max_number_requested)
     603             :       break;
     604             : 
     605             :     if(strnequal(servrec->serv.name, lp_netbios_name(),15))
     606             :       continue;
     607             : 
     608             :     if(!(servrec->serv.type & SV_TYPE_BACKUP_BROWSER))
     609             :       continue;
     610             : 
     611             :     strlcpy(p, servrec->serv.name, 16);
     612             :     strupper_m(p);
     613             :     count++;
     614             : 
     615             :     DEBUG(5,("send_backup_list_response: Adding server %s number %d\n",
     616             :               p, count));
     617             : 
     618             :     p = skip_string(outbuf,sizeof(outbuf),p);
     619             :   }
     620             : #endif
     621             : 
     622           0 :         SCVAL(countptr, 0, count);
     623             : 
     624           0 :         pull_ascii_nstring(send_to_namestr, sizeof(send_to_namestr), send_to_name->name);
     625             : 
     626           0 :         DEBUG(4,("send_backup_list_response: sending response to %s<00> IP %s with %d servers.\n",
     627             :                 send_to_namestr, inet_ntoa(sendto_ip), count));
     628             : 
     629           0 :         send_mailslot(True, BROWSE_MAILSLOT,
     630           0 :                 outbuf,PTR_DIFF(p,outbuf),
     631             :                 lp_netbios_name(), 0,
     632             :                 send_to_namestr,0,
     633             :                 sendto_ip, subrec->myip, port);
     634             : }
     635             : 
     636             : /*******************************************************************
     637             :   Process a send backup list request packet.
     638             : 
     639             :   A client sends a backup list request to ask for a list of servers on
     640             :   the net that maintain server lists for a domain. A server is then
     641             :   chosen from this list to send NetServerEnum commands to to list
     642             :   available servers.
     643             : 
     644             : ********************************************************************/
     645             : 
     646           0 : void process_get_backup_list_request(struct subnet_record *subrec,
     647             :                                      struct packet_struct *p,const char *buf)
     648             : {
     649           0 :         struct dgram_packet *dgram = &p->packet.dgram;
     650             :         struct work_record *work;
     651           0 :         unsigned char max_number_requested = CVAL(buf,0);
     652           0 :         uint32_t token = IVAL(buf,1); /* Sender's key index for the workgroup. */
     653           0 :         int name_type = dgram->dest_name.name_type;
     654             :         unstring workgroup_name;
     655           0 :         struct subnet_record *search_subrec = subrec;
     656             : 
     657           0 :         pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
     658             : 
     659           0 :         DEBUG(3,("process_get_backup_list_request: request from %s IP %s to %s.\n",
     660             :                 nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
     661             :                 nmb_namestr(&dgram->dest_name)));
     662             : 
     663             :         /* We have to be a master browser, or a domain master browser
     664             :                 for the requested workgroup. That means it must be our
     665             :                 workgroup. */
     666             : 
     667           0 :         if(strequal(workgroup_name, lp_workgroup()) == False) {
     668           0 :                 DEBUG(7,("process_get_backup_list_request: Ignoring announce request for workgroup %s.\n",
     669             :                         workgroup_name));
     670           0 :                 goto done;
     671             :         }
     672             : 
     673           0 :         if((work = find_workgroup_on_subnet(search_subrec, workgroup_name)) == NULL) {
     674           0 :                 DEBUG(0,("process_get_backup_list_request: Cannot find workgroup %s on \
     675             : subnet %s.\n", workgroup_name, search_subrec->subnet_name));
     676           0 :                 goto done;
     677             :         }
     678             : 
     679             :         /*
     680             :          * If the packet was sent to WORKGROUP<1b> instead
     681             :          * of WORKGROUP<1d> then it was unicast to us a domain master
     682             :          * browser. Change search subrec to unicast.
     683             :          */
     684             : 
     685           0 :         if(name_type == 0x1b) {
     686             :                 /* We must be a domain master browser in order to
     687             :                         process this packet. */
     688             : 
     689           0 :                 if(!AM_DOMAIN_MASTER_BROWSER(work)) {
     690           0 :                         DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
     691             : and I am not a domain master browser.\n", workgroup_name));
     692           0 :                         goto done;
     693             :                 }
     694             : 
     695           0 :                 search_subrec = unicast_subnet;
     696           0 :         } else if (name_type == 0x1d) {
     697             :                 /* We must be a local master browser in order to process this packet. */
     698             : 
     699           0 :                 if(!AM_LOCAL_MASTER_BROWSER(work)) {
     700           0 :                         DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
     701             : and I am not a local master browser.\n", workgroup_name));
     702           0 :                         goto done;
     703             :                 }
     704             :         } else {
     705           0 :                 DEBUG(0,("process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d.\n",
     706             :                         name_type));
     707           0 :                 goto done;
     708             :         }
     709             : 
     710           0 :         send_backup_list_response(subrec, work, &dgram->source_name,
     711             :                         max_number_requested, token, p->ip, p->port);
     712             : 
     713           0 : done:
     714           0 :         return;
     715             : }
     716             : 
     717             : /*******************************************************************
     718             :   Process a reset browser state packet.
     719             : 
     720             :   Diagnostic packet:
     721             :   0x1 - Stop being a master browser and become a backup browser.
     722             :   0x2 - Discard browse lists, stop being a master browser, try again.
     723             :   0x4 - Stop being a master browser forever.
     724             : 
     725             : ******************************************************************/
     726             : 
     727           0 : void process_reset_browser(struct subnet_record *subrec,
     728             :                                   struct packet_struct *p,const char *buf)
     729             : {
     730           0 :         struct dgram_packet *dgram = &p->packet.dgram;
     731           0 :         int state = CVAL(buf,0);
     732             :         struct subnet_record *sr;
     733             : 
     734           0 :         DEBUG(1,("process_reset_browser: received diagnostic browser reset \
     735             : request from %s IP %s state=0x%X\n",
     736             :                 nmb_namestr(&dgram->source_name), inet_ntoa(p->ip), state));
     737             : 
     738             :         /* Stop being a local master browser on all our broadcast subnets. */
     739           0 :         if (state & 0x1) {
     740           0 :                 for (sr = FIRST_SUBNET; sr; sr = NEXT_SUBNET_EXCLUDING_UNICAST(sr)) {
     741             :                         struct work_record *work;
     742           0 :                         for (work = sr->workgrouplist; work; work = work->next) {
     743           0 :                                 if (AM_LOCAL_MASTER_BROWSER(work))
     744           0 :                                         unbecome_local_master_browser(sr, work, True);
     745             :                         }
     746             :                 }
     747             :         }
     748             : 
     749             :         /* Discard our browse lists. */
     750           0 :         if (state & 0x2) {
     751             :                 /*
     752             :                  * Calling expire_workgroups_and_servers with a -1
     753             :                  * time causes all servers not marked with a PERMANENT_TTL
     754             :                  * on the workgroup lists to be discarded, and all
     755             :                  * workgroups with empty server lists to be discarded.
     756             :                  * This means we keep our own server names and workgroup
     757             :                  * as these have a PERMANENT_TTL.
     758             :                  */
     759             : 
     760           0 :                 expire_workgroups_and_servers(-1);
     761             :         }
     762             : 
     763             :         /* Request to stop browsing altogether. */
     764           0 :         if (state & 0x4)
     765           0 :                 DEBUG(1,("process_reset_browser: ignoring request to stop being a browser.\n"));
     766           0 : }
     767             : 
     768             : /*******************************************************************
     769             :   Process an announcement request packet.
     770             :   We don't respond immediately, we just check it's a request for
     771             :   our workgroup and then set the flag telling the announce code
     772             :   in nmbd_sendannounce.c:announce_my_server_names that an
     773             :   announcement is needed soon.
     774             : ******************************************************************/
     775             : 
     776           7 : void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, const char *buf)
     777             : {
     778           7 :         struct dgram_packet *dgram = &p->packet.dgram;
     779             :         struct work_record *work;
     780             :         unstring workgroup_name;
     781             : 
     782           7 :         pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
     783           7 :         DEBUG(3,("process_announce_request: Announce request from %s IP %s to %s.\n",
     784             :                 nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
     785             :                 nmb_namestr(&dgram->dest_name)));
     786             : 
     787             :         /* We only send announcement requests on our workgroup. */
     788           7 :         if(strequal(workgroup_name, lp_workgroup()) == False) {
     789           0 :                 DEBUG(7,("process_announce_request: Ignoring announce request for workgroup %s.\n",
     790             :                         workgroup_name));
     791           0 :                 goto done;
     792             :         }
     793             : 
     794           7 :         if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL) {
     795           0 :                 DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
     796             :                         workgroup_name));
     797           0 :                 goto done;
     798             :         }
     799             : 
     800           7 :         work->needannounce = True;
     801           7 : done:
     802           7 :         return;
     803             : }
     804             : 
     805             : /*******************************************************************
     806             :   Process a LanMan announcement request packet.
     807             :   We don't respond immediately, we just check it's a request for
     808             :   our workgroup and then set the flag telling that we have found
     809             :   a LanMan client (DOS or OS/2) and that we will have to start
     810             :   sending LanMan announcements (unless specifically disabled
     811             :   through the "lm announce" parameter in smb.conf)
     812             : ******************************************************************/
     813             : 
     814           0 : void process_lm_announce_request(struct subnet_record *subrec, struct packet_struct *p, const char *buf, int len)
     815             : {
     816           0 :         struct dgram_packet *dgram = &p->packet.dgram;
     817             :         unstring workgroup_name;
     818             : 
     819           0 :         pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name);
     820           0 :         DEBUG(3,("process_lm_announce_request: Announce request from %s IP %s to %s.\n",
     821             :                 nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
     822             :                 nmb_namestr(&dgram->dest_name)));
     823             : 
     824             :         /* We only send announcement requests on our workgroup. */
     825           0 :         if(strequal(workgroup_name, lp_workgroup()) == False) {
     826           0 :                 DEBUG(7,("process_lm_announce_request: Ignoring announce request for workgroup %s.\n",
     827             :                         workgroup_name));
     828           0 :                 goto done;
     829             :         }
     830             : 
     831           0 :         if(find_workgroup_on_subnet(subrec, workgroup_name) == NULL) {
     832           0 :                 DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
     833             :                         workgroup_name));
     834           0 :                 goto done;
     835             :         }
     836             : 
     837           0 :         found_lm_clients = True;
     838             : 
     839           0 : done:
     840           0 :         return;
     841             : }

Generated by: LCOV version 1.14