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