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