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