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   SMB Version handling
9   Copyright (C) John H Terpstra 1995-1998
10
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 2 of the License, or
14   (at your option) any later version.
15
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
25*/
26
27#include "includes.h"
28
29extern int  updatecount;
30extern BOOL found_lm_clients;
31
32/****************************************************************************
33 Send a browser reset packet.
34**************************************************************************/
35
36void send_browser_reset(int reset_type, const char *to_name, int to_type, struct in_addr to_ip)
37{
38	pstring outbuf;
39	char *p;
40
41	DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
42		reset_type, to_name, to_type, inet_ntoa(to_ip) ));
43
44	memset(outbuf,'\0',sizeof(outbuf));
45	p = outbuf;
46	SCVAL(p,0,ANN_ResetBrowserState);
47	p++;
48	SCVAL(p,0,reset_type);
49	p++;
50
51	send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
52		global_myname(), 0x0, to_name, to_type, to_ip,
53		FIRST_SUBNET->myip, DGRAM_PORT);
54}
55
56/****************************************************************************
57  Broadcast a packet to the local net requesting that all servers in this
58  workgroup announce themselves to us.
59  **************************************************************************/
60
61void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
62{
63	pstring outbuf;
64	char *p;
65
66	work->needannounce = True;
67
68	DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
69to subnet %s\n", work->work_group, subrec->subnet_name));
70
71	memset(outbuf,'\0',sizeof(outbuf));
72	p = outbuf;
73	SCVAL(p,0,ANN_AnnouncementRequest);
74	p++;
75
76	SCVAL(p,0,work->token); /* (local) Unique workgroup token id. */
77	p++;
78	p +=  push_string(NULL, p+1, global_myname(), 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
79
80	send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
81		global_myname(), 0x0, work->work_group,0x1e, subrec->bcast_ip,
82		subrec->myip, DGRAM_PORT);
83}
84
85/****************************************************************************
86  Broadcast an announcement.
87  **************************************************************************/
88
89static void send_announcement(struct subnet_record *subrec, int announce_type,
90                              const char *from_name, const char *to_name, int to_type, struct in_addr to_ip,
91                              time_t announce_interval,
92                              const char *server_name, int server_type, const char *server_comment)
93{
94	pstring outbuf;
95	char *p;
96
97	memset(outbuf,'\0',sizeof(outbuf));
98	p = outbuf+1;
99
100	SCVAL(outbuf,0,announce_type);
101
102	/* Announcement parameters. */
103	SCVAL(p,0,updatecount);
104	SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
105
106	push_string(NULL, p+5, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
107
108	SCVAL(p,21,lp_major_announce_version()); /* Major version. */
109	SCVAL(p,22,lp_minor_announce_version()); /* Minor version. */
110
111	SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
112	/* Browse version: got from NT/AS 4.00  - Value defined in smb.h (JHT). */
113	SSVAL(p,27,BROWSER_ELECTION_VERSION);
114	SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
115
116	p += 31 + push_string(NULL, p+31, server_comment, -1, STR_ASCII|STR_TERMINATE);
117
118	send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
119			from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
120			DGRAM_PORT);
121}
122
123/****************************************************************************
124  Broadcast a LanMan announcement.
125**************************************************************************/
126
127static void send_lm_announcement(struct subnet_record *subrec, int announce_type,
128                              char *from_name, char *to_name, int to_type, struct in_addr to_ip,
129                              time_t announce_interval,
130                              char *server_name, int server_type, char *server_comment)
131{
132	pstring outbuf;
133	char *p=outbuf;
134
135	memset(outbuf,'\0',sizeof(outbuf));
136
137	SSVAL(p,0,announce_type);
138	SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
139	SCVAL(p,6,lp_major_announce_version()); /* Major version. */
140	SCVAL(p,7,lp_minor_announce_version()); /* Minor version. */
141	SSVAL(p,8,announce_interval);            /* In seconds - according to spec. */
142
143	p += 10;
144	p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
145	p += push_string(NULL, p, server_comment, sizeof(pstring)-15, STR_ASCII|STR_UPPER|STR_TERMINATE);
146
147	send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
148		from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
149		DGRAM_PORT);
150}
151
152/****************************************************************************
153 We are a local master browser. Announce this to WORKGROUP<1e>.
154****************************************************************************/
155
156static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
157                                           struct server_record *servrec)
158{
159	/* Ensure we don't have the prohibited bit set. */
160	uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
161
162	DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
163		type, global_myname(), subrec->subnet_name, work->work_group));
164
165	send_announcement(subrec, ANN_LocalMasterAnnouncement,
166			global_myname(),                 /* From nbt name. */
167			work->work_group, 0x1e,          /* To nbt name. */
168			subrec->bcast_ip,                /* To ip. */
169			work->announce_interval,         /* Time until next announce. */
170			global_myname(),                 /* Name to announce. */
171			type,                            /* Type field. */
172			servrec->serv.comment);
173}
174
175/****************************************************************************
176 Announce the workgroup WORKGROUP to MSBROWSE<01>.
177****************************************************************************/
178
179static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
180{
181	DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
182		subrec->subnet_name, work->work_group));
183
184	send_announcement(subrec, ANN_DomainAnnouncement,
185			global_myname(),                 /* From nbt name. */
186			MSBROWSE, 0x1,                   /* To nbt name. */
187			subrec->bcast_ip,                /* To ip. */
188			work->announce_interval,         /* Time until next announce. */
189			work->work_group,                /* Name to announce. */
190			SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT,  /* workgroup announce flags. */
191			global_myname());                /* From name as comment. */
192}
193
194/****************************************************************************
195 Announce the given host to WORKGROUP<1d>.
196****************************************************************************/
197
198static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
199                                   struct server_record *servrec)
200{
201	/* Ensure we don't have the prohibited bits set. */
202	uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
203
204	DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
205		type, servrec->serv.name, subrec->subnet_name, work->work_group));
206
207	send_announcement(subrec, ANN_HostAnnouncement,
208			servrec->serv.name,              /* From nbt name. */
209			work->work_group, 0x1d,          /* To nbt name. */
210			subrec->bcast_ip,                /* To ip. */
211			work->announce_interval,         /* Time until next announce. */
212			servrec->serv.name,              /* Name to announce. */
213			type,                            /* Type field. */
214			servrec->serv.comment);
215}
216
217/****************************************************************************
218 Announce the given LanMan host
219****************************************************************************/
220
221static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
222                                   struct server_record *servrec, int lm_interval)
223{
224	/* Ensure we don't have the prohibited bits set. */
225	uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
226
227	DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
228		type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
229
230	send_lm_announcement(subrec, ANN_HostAnnouncement,
231			servrec->serv.name,              /* From nbt name. */
232			work->work_group, 0x00,          /* To nbt name. */
233			subrec->bcast_ip,                /* To ip. */
234			lm_interval,                     /* Time until next announce. */
235			servrec->serv.name,              /* Name to announce (fstring not netbios name struct). */
236			type,                            /* Type field. */
237			servrec->serv.comment);
238}
239
240/****************************************************************************
241  Announce a server record.
242  ****************************************************************************/
243
244static void announce_server(struct subnet_record *subrec, struct work_record *work,
245                     struct server_record *servrec)
246{
247	/* Only do domain announcements if we are a master and it's
248		our primary name we're being asked to announce. */
249
250	if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname(),servrec->serv.name)) {
251		send_local_master_announcement(subrec, work, servrec);
252		send_workgroup_announcement(subrec, work);
253	} else {
254		send_host_announcement(subrec, work, servrec);
255	}
256}
257
258/****************************************************************************
259  Go through all my registered names on all broadcast subnets and announce
260  them if the timeout requires it.
261  **************************************************************************/
262
263void announce_my_server_names(time_t t)
264{
265	struct subnet_record *subrec;
266
267	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
268		struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
269
270		if(work) {
271			struct server_record *servrec;
272
273			if (work->needannounce) {
274				/* Drop back to a max 3 minute announce. This is to prevent a
275					single lost packet from breaking things for too long. */
276
277				work->announce_interval = MIN(work->announce_interval,
278							CHECK_TIME_MIN_HOST_ANNCE*60);
279				work->lastannounce_time = t - (work->announce_interval+1);
280				work->needannounce = False;
281			}
282
283			/* Announce every minute at first then progress to every 12 mins */
284			if ((t - work->lastannounce_time) < work->announce_interval)
285				continue;
286
287			if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
288				work->announce_interval += 60;
289
290			work->lastannounce_time = t;
291
292			for (servrec = work->serverlist; servrec; servrec = servrec->next) {
293				if (is_myname(servrec->serv.name))
294					announce_server(subrec, work, servrec);
295			}
296		} /* if work */
297	} /* for subrec */
298}
299
300/****************************************************************************
301  Go through all my registered names on all broadcast subnets and announce
302  them as a LanMan server if the timeout requires it.
303**************************************************************************/
304
305void announce_my_lm_server_names(time_t t)
306{
307	struct subnet_record *subrec;
308	static time_t last_lm_announce_time=0;
309	int announce_interval = lp_lm_interval();
310	int lm_announce = lp_lm_announce();
311
312	if ((announce_interval <= 0) || (lm_announce <= 0)) {
313		/* user absolutely does not want LM announcements to be sent. */
314		return;
315	}
316
317	if ((lm_announce >= 2) && (!found_lm_clients)) {
318		/* has been set to 2 (Auto) but no LM clients detected (yet). */
319		return;
320	}
321
322	/* Otherwise: must have been set to 1 (Yes), or LM clients *have*
323		been detected. */
324
325	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
326		struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
327
328		if(work) {
329			struct server_record *servrec;
330
331			if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
332				continue;
333
334			last_lm_announce_time = t;
335
336			for (servrec = work->serverlist; servrec; servrec = servrec->next) {
337				if (is_myname(servrec->serv.name))
338					/* skipping equivalent of announce_server() */
339					send_lm_host_announcement(subrec, work, servrec, announce_interval);
340			}
341		} /* if work */
342	} /* for subrec */
343}
344
345/* Announce timer. Moved into global static so it can be reset
346   when a machine becomes a local master browser. */
347static time_t announce_timer_last=0;
348
349/****************************************************************************
350 Reset the announce_timer so that a local master browser announce will be done
351 immediately.
352 ****************************************************************************/
353
354void reset_announce_timer(void)
355{
356	announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
357}
358
359/****************************************************************************
360  Announce myself as a local master browser to a domain master browser.
361  **************************************************************************/
362
363void announce_myself_to_domain_master_browser(time_t t)
364{
365	struct subnet_record *subrec;
366	struct work_record *work;
367
368	if(!we_are_a_wins_client()) {
369		DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
370		return;
371	}
372
373	if (!announce_timer_last)
374		announce_timer_last = t;
375
376	if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60)) {
377		DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
378			(int)t, (int)announce_timer_last,
379			CHECK_TIME_MST_ANNOUNCE * 60 ));
380		return;
381	}
382
383	announce_timer_last = t;
384
385	/* Look over all our broadcast subnets to see if any of them
386		has the state set as local master browser. */
387
388	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
389		for (work = subrec->workgrouplist; work; work = work->next) {
390			if (AM_LOCAL_MASTER_BROWSER(work)) {
391				DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
392workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
393
394				/* Look in nmbd_browsersync.c for the rest of this code. */
395				announce_and_sync_with_domain_master_browser(subrec, work);
396			}
397		}
398	}
399}
400
401/****************************************************************************
402Announce all samba's server entries as 'gone'.
403This must *only* be called on shutdown.
404****************************************************************************/
405
406void announce_my_servers_removed(void)
407{
408	int announce_interval = lp_lm_interval();
409	int lm_announce = lp_lm_announce();
410	struct subnet_record *subrec;
411
412	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
413		struct work_record *work;
414		for (work = subrec->workgrouplist; work; work = work->next) {
415			struct server_record *servrec;
416
417			work->announce_interval = 0;
418			for (servrec = work->serverlist; servrec; servrec = servrec->next) {
419				if (!is_myname(servrec->serv.name))
420					continue;
421				servrec->serv.type = 0;
422				if(AM_LOCAL_MASTER_BROWSER(work))
423					send_local_master_announcement(subrec, work, servrec);
424				send_host_announcement(subrec, work, servrec);
425
426				if ((announce_interval <= 0) || (lm_announce <= 0)) {
427					/* user absolutely does not want LM announcements to be sent. */
428					continue;
429				}
430
431				if ((lm_announce >= 2) && (!found_lm_clients)) {
432					/* has been set to 2 (Auto) but no LM clients detected (yet). */
433					continue;
434				}
435
436				/*
437				 * lm announce was set or we have seen lm announcements, so do
438				 * a lm announcement of host removed.
439				 */
440
441				send_lm_host_announcement(subrec, work, servrec, 0);
442			}
443		}
444	}
445}
446
447/****************************************************************************
448  Do all the "remote" announcements. These are used to put ourselves
449  on a remote browse list. They are done blind, no checking is done to
450  see if there is actually a local master browser at the other end.
451  **************************************************************************/
452
453void announce_remote(time_t t)
454{
455	char *s;
456	const char *ptr;
457	static time_t last_time = 0;
458	pstring s2;
459	struct in_addr addr;
460	char *comment;
461	int stype = lp_default_server_announce();
462
463	if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
464		return;
465
466	last_time = t;
467
468	s = lp_remote_announce();
469	if (!*s)
470		return;
471
472	comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
473
474	for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
475		/* The entries are of the form a.b.c.d/WORKGROUP with
476				WORKGROUP being optional */
477		const char *wgroup;
478		char *pwgroup;
479		int i;
480
481		pwgroup = strchr_m(s2,'/');
482		if (pwgroup)
483			*pwgroup++ = 0;
484		if (!pwgroup || !*pwgroup)
485			wgroup = lp_workgroup();
486		else
487			wgroup = pwgroup;
488
489		addr = *interpret_addr2(s2);
490
491		/* Announce all our names including aliases */
492		/* Give the ip address as the address of our first
493				broadcast subnet. */
494
495		for(i=0; my_netbios_names(i); i++) {
496			const char *name = my_netbios_names(i);
497
498			DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
499				name, inet_ntoa(addr) ));
500
501			send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
502						name,                      /* From nbt name. */
503						wgroup, 0x1d,              /* To nbt name. */
504						addr,                      /* To ip. */
505						REMOTE_ANNOUNCE_INTERVAL,  /* Time until next announce. */
506						name,                      /* Name to announce. */
507						stype,                     /* Type field. */
508						comment);
509		}
510	}
511}
512
513/****************************************************************************
514  Implement the 'remote browse sync' feature Andrew added.
515  These are used to put our browse lists into remote browse lists.
516**************************************************************************/
517
518void browse_sync_remote(time_t t)
519{
520	char *s;
521	const char *ptr;
522	static time_t last_time = 0;
523	pstring s2;
524	struct in_addr addr;
525	struct work_record *work;
526	pstring outbuf;
527	char *p;
528	fstring myname;
529
530	if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
531		return;
532
533	last_time = t;
534
535	s = lp_remote_browse_sync();
536	if (!*s)
537		return;
538
539	/*
540	 * We only do this if we are the local master browser
541	 * for our workgroup on the firsst subnet.
542	 */
543
544	if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL) {
545		DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
546			lp_workgroup(), FIRST_SUBNET->subnet_name ));
547		return;
548	}
549
550	if(!AM_LOCAL_MASTER_BROWSER(work)) {
551		DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
552for workgroup %s on subnet %s.\n", lp_workgroup(), FIRST_SUBNET->subnet_name ));
553		return;
554	}
555
556	memset(outbuf,'\0',sizeof(outbuf));
557	p = outbuf;
558	SCVAL(p,0,ANN_MasterAnnouncement);
559	p++;
560
561	fstrcpy(myname, global_myname());
562	strupper_m(myname);
563	myname[15]='\0';
564	push_pstring_base(p, myname, outbuf);
565
566	p = skip_string(p,1);
567
568	for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
569		/* The entries are of the form a.b.c.d */
570		addr = *interpret_addr2(s2);
571
572		DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
573			global_myname(), inet_ntoa(addr) ));
574
575		send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
576			global_myname(), 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
577	}
578}
579