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