2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1998
6 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7 Copyright (C) Jeremy Allison 1994-1998
10 Copyright (C) John H Terpstra 1995-1998
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 extern int DEBUGLEVEL;
31 extern pstring global_myname;
32 extern fstring global_myworkgroup;
33 extern char **my_netbios_names;
34 extern int updatecount;
35 extern BOOL found_lm_clients;
37 /****************************************************************************
38 Send a browser reset packet.
39 **************************************************************************/
41 void send_browser_reset(int reset_type, char *to_name, int to_type, struct in_addr to_ip)
46 DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
47 reset_type, to_name, to_type, inet_ntoa(to_ip) ));
49 memset(outbuf,'\0',sizeof(outbuf));
51 CVAL(p,0) = ANN_ResetBrowserState;
53 CVAL(p,0) = reset_type;
56 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
57 global_myname, 0x0, to_name, to_type, to_ip,
58 FIRST_SUBNET->myip, DGRAM_PORT);
61 /****************************************************************************
62 Broadcast a packet to the local net requesting that all servers in this
63 workgroup announce themselves to us.
64 **************************************************************************/
66 void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
71 work->needannounce = True;
73 DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
74 to subnet %s\n", work->work_group, subrec->subnet_name));
76 memset(outbuf,'\0',sizeof(outbuf));
78 CVAL(p,0) = ANN_AnnouncementRequest;
81 CVAL(p,0) = work->token; /* (local) Unique workgroup token id. */
83 p += push_string(NULL, p+1, global_myname, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
85 send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
86 global_myname, 0x0, work->work_group,0x1e, subrec->bcast_ip,
87 subrec->myip, DGRAM_PORT);
90 /****************************************************************************
91 Broadcast an announcement.
92 **************************************************************************/
94 static void send_announcement(struct subnet_record *subrec, int announce_type,
95 char *from_name, char *to_name, int to_type, struct in_addr to_ip,
96 time_t announce_interval,
97 char *server_name, int server_type, char *server_comment)
102 memset(outbuf,'\0',sizeof(outbuf));
105 CVAL(outbuf,0) = announce_type;
107 /* Announcement parameters. */
108 CVAL(p,0) = updatecount;
109 SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
111 push_string(NULL, p+5, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
113 CVAL(p,21) = lp_major_announce_version(); /* Major version. */
114 CVAL(p,22) = lp_minor_announce_version(); /* Minor version. */
116 SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
117 /* Browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT). */
118 SSVAL(p,27,BROWSER_ELECTION_VERSION);
119 SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
121 p += 31 + push_string(NULL, p+31, server_comment, -1, STR_ASCII|STR_TERMINATE);
123 send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
124 from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
128 /****************************************************************************
129 Broadcast a LanMan announcement.
130 **************************************************************************/
132 static void send_lm_announcement(struct subnet_record *subrec, int announce_type,
133 char *from_name, char *to_name, int to_type, struct in_addr to_ip,
134 time_t announce_interval,
135 char *server_name, int server_type, char *server_comment)
140 memset(outbuf,'\0',sizeof(outbuf));
142 SSVAL(p,0,announce_type);
143 SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
144 CVAL(p,6) = lp_major_announce_version(); /* Major version. */
145 CVAL(p,7) = lp_minor_announce_version(); /* Minor version. */
146 SSVAL(p,8,announce_interval); /* In seconds - according to spec. */
149 /*StrnCpy(p,server_name,15);
151 p = skip_string(p,1);
152 pstrcpy(p,server_comment);
153 p = skip_string(p,1);*/
154 p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
155 p += push_string(NULL, p, server_comment, sizeof(pstring)-15, STR_ASCII|STR_UPPER|STR_TERMINATE);
157 send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
158 from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
162 /****************************************************************************
163 We are a local master browser. Announce this to WORKGROUP<1e>.
164 ****************************************************************************/
166 static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
167 struct server_record *servrec)
169 /* Ensure we don't have the prohibited bit set. */
170 uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
172 DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
173 type, global_myname, subrec->subnet_name, work->work_group));
175 send_announcement(subrec, ANN_LocalMasterAnnouncement,
176 global_myname, /* From nbt name. */
177 work->work_group, 0x1e, /* To nbt name. */
178 subrec->bcast_ip, /* To ip. */
179 work->announce_interval, /* Time until next announce. */
180 global_myname, /* Name to announce. */
181 type, /* Type field. */
182 servrec->serv.comment);
185 /****************************************************************************
186 Announce the workgroup WORKGROUP to MSBROWSE<01>.
187 ****************************************************************************/
189 static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
191 DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
192 subrec->subnet_name, work->work_group));
194 send_announcement(subrec, ANN_DomainAnnouncement,
195 global_myname, /* From nbt name. */
196 MSBROWSE, 0x1, /* To nbt name. */
197 subrec->bcast_ip, /* To ip. */
198 work->announce_interval, /* Time until next announce. */
199 work->work_group, /* Name to announce. */
200 SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT, /* workgroup announce flags. */
201 global_myname); /* From name as comment. */
204 /****************************************************************************
205 Announce the given host to WORKGROUP<1d>.
206 ****************************************************************************/
208 static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
209 struct server_record *servrec)
211 /* Ensure we don't have the prohibited bits set. */
212 uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
214 DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
215 type, servrec->serv.name, subrec->subnet_name, work->work_group));
217 send_announcement(subrec, ANN_HostAnnouncement,
218 servrec->serv.name, /* From nbt name. */
219 work->work_group, 0x1d, /* To nbt name. */
220 subrec->bcast_ip, /* To ip. */
221 work->announce_interval, /* Time until next announce. */
222 servrec->serv.name, /* Name to announce. */
223 type, /* Type field. */
224 servrec->serv.comment);
227 /****************************************************************************
228 Announce the given LanMan host
229 ****************************************************************************/
231 static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
232 struct server_record *servrec, int lm_interval)
234 /* Ensure we don't have the prohibited bits set. */
235 uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
237 DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
238 type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
240 send_lm_announcement(subrec, ANN_HostAnnouncement,
241 servrec->serv.name, /* From nbt name. */
242 work->work_group, 0x00, /* To nbt name. */
243 subrec->bcast_ip, /* To ip. */
244 lm_interval, /* Time until next announce. */
245 servrec->serv.name, /* Name to announce. */
246 type, /* Type field. */
247 servrec->serv.comment);
250 /****************************************************************************
251 Announce a server record.
252 ****************************************************************************/
254 static void announce_server(struct subnet_record *subrec, struct work_record *work,
255 struct server_record *servrec)
257 /* Only do domain announcements if we are a master and it's
258 our primary name we're being asked to announce. */
260 if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname,servrec->serv.name))
262 send_local_master_announcement(subrec, work, servrec);
263 send_workgroup_announcement(subrec, work);
267 send_host_announcement(subrec, work, servrec);
271 /****************************************************************************
272 Go through all my registered names on all broadcast subnets and announce
273 them if the timeout requires it.
274 **************************************************************************/
276 void announce_my_server_names(time_t t)
278 struct subnet_record *subrec;
280 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
282 struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup);
286 struct server_record *servrec;
288 if (work->needannounce)
290 /* Drop back to a max 3 minute announce. This is to prevent a
291 single lost packet from breaking things for too long. */
293 work->announce_interval = MIN(work->announce_interval,
294 CHECK_TIME_MIN_HOST_ANNCE*60);
295 work->lastannounce_time = t - (work->announce_interval+1);
296 work->needannounce = False;
299 /* Announce every minute at first then progress to every 12 mins */
300 if ((t - work->lastannounce_time) < work->announce_interval)
303 if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
304 work->announce_interval += 60;
306 work->lastannounce_time = t;
308 for (servrec = work->serverlist; servrec; servrec = servrec->next)
310 if (is_myname(servrec->serv.name))
311 announce_server(subrec, work, servrec);
317 /****************************************************************************
318 Go through all my registered names on all broadcast subnets and announce
319 them as a LanMan server if the timeout requires it.
320 **************************************************************************/
322 void announce_my_lm_server_names(time_t t)
324 struct subnet_record *subrec;
325 static time_t last_lm_announce_time=0;
326 int announce_interval = lp_lm_interval();
327 int lm_announce = lp_lm_announce();
329 if ((announce_interval <= 0) || (lm_announce <= 0))
331 /* user absolutely does not want LM announcements to be sent. */
335 if ((lm_announce >= 2) && (!found_lm_clients))
337 /* has been set to 2 (Auto) but no LM clients detected (yet). */
341 /* Otherwise: must have been set to 1 (Yes), or LM clients *have*
344 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
346 struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup);
350 struct server_record *servrec;
352 if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
355 last_lm_announce_time = t;
357 for (servrec = work->serverlist; servrec; servrec = servrec->next)
359 if (is_myname(servrec->serv.name))
360 /* skipping equivalent of announce_server() */
361 send_lm_host_announcement(subrec, work, servrec, announce_interval);
367 /* Announce timer. Moved into global static so it can be reset
368 when a machine becomes a local master browser. */
369 static time_t announce_timer_last=0;
371 /****************************************************************************
372 Reset the announce_timer so that a local master browser announce will be done
374 ****************************************************************************/
376 void reset_announce_timer(void)
378 announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
381 /****************************************************************************
382 Announce myself as a local master browser to a domain master browser.
383 **************************************************************************/
385 void announce_myself_to_domain_master_browser(time_t t)
387 struct subnet_record *subrec;
388 struct work_record *work;
390 if(!we_are_a_wins_client())
392 DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
396 if (!announce_timer_last)
397 announce_timer_last = t;
399 if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60))
401 DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
402 (int)t, (int)announce_timer_last,
403 CHECK_TIME_MST_ANNOUNCE * 60 ));
407 announce_timer_last = t;
409 /* Look over all our broadcast subnets to see if any of them
410 has the state set as local master browser. */
412 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
414 for (work = subrec->workgrouplist; work; work = work->next)
416 if (AM_LOCAL_MASTER_BROWSER(work))
418 DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
419 workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
421 /* Look in nmbd_browsersync.c for the rest of this code. */
422 announce_and_sync_with_domain_master_browser(subrec, work);
428 /****************************************************************************
429 Announce all samba's server entries as 'gone'.
430 This must *only* be called on shutdown.
431 ****************************************************************************/
433 void announce_my_servers_removed(void)
435 int announce_interval = lp_lm_interval();
436 int lm_announce = lp_lm_announce();
437 struct subnet_record *subrec;
439 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
441 struct work_record *work;
442 for (work = subrec->workgrouplist; work; work = work->next)
444 struct server_record *servrec;
446 work->announce_interval = 0;
447 for (servrec = work->serverlist; servrec; servrec = servrec->next)
449 if (!is_myname(servrec->serv.name))
451 servrec->serv.type = 0;
452 if(AM_LOCAL_MASTER_BROWSER(work))
453 send_local_master_announcement(subrec, work, servrec);
454 send_host_announcement(subrec, work, servrec);
457 if ((announce_interval <= 0) || (lm_announce <= 0))
459 /* user absolutely does not want LM announcements to be sent. */
463 if ((lm_announce >= 2) && (!found_lm_clients))
465 /* has been set to 2 (Auto) but no LM clients detected (yet). */
470 * lm announce was set or we have seen lm announcements, so do
471 * a lm announcement of host removed.
474 send_lm_host_announcement(subrec, work, servrec, 0);
480 /****************************************************************************
481 Do all the "remote" announcements. These are used to put ourselves
482 on a remote browse list. They are done blind, no checking is done to
483 see if there is actually a local master browser at the other end.
484 **************************************************************************/
486 void announce_remote(time_t t)
489 static time_t last_time = 0;
493 int stype = lp_default_server_announce();
495 if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
500 s = lp_remote_announce();
504 comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
506 for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); )
508 /* The entries are of the form a.b.c.d/WORKGROUP with
509 WORKGROUP being optional */
513 wgroup = strchr(s2,'/');
516 if (!wgroup || !*wgroup)
517 wgroup = global_myworkgroup;
519 addr = *interpret_addr2(s2);
521 /* Announce all our names including aliases */
522 /* Give the ip address as the address of our first
525 for(i=0; my_netbios_names[i]; i++)
527 char *name = my_netbios_names[i];
529 DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
530 name, inet_ntoa(addr) ));
532 send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
533 name, /* From nbt name. */
534 wgroup, 0x1d, /* To nbt name. */
536 REMOTE_ANNOUNCE_INTERVAL, /* Time until next announce. */
537 name, /* Name to announce. */
538 stype, /* Type field. */
544 /****************************************************************************
545 Implement the 'remote browse sync' feature Andrew added.
546 These are used to put our browse lists into remote browse lists.
547 **************************************************************************/
549 void browse_sync_remote(time_t t)
552 static time_t last_time = 0;
555 struct work_record *work;
559 if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
564 s = lp_remote_browse_sync();
569 * We only do this if we are the local master browser
570 * for our workgroup on the firsst subnet.
573 if((work = find_workgroup_on_subnet(FIRST_SUBNET, global_myworkgroup)) == NULL)
575 DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
576 global_myworkgroup, FIRST_SUBNET->subnet_name ));
580 if(!AM_LOCAL_MASTER_BROWSER(work))
582 DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
583 for workgroup %s on subnet %s.\n", global_myworkgroup, FIRST_SUBNET->subnet_name ));
587 memset(outbuf,'\0',sizeof(outbuf));
589 CVAL(p,0) = ANN_MasterAnnouncement;
592 StrnCpy(p,global_myname,15);
594 p = skip_string(p,1);
596 for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); )
598 /* The entries are of the form a.b.c.d */
599 addr = *interpret_addr2(s2);
601 DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
602 global_myname, inet_ntoa(addr) ));
604 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
605 global_myname, 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);