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