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