2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1995
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
32 extern int DEBUGLEVEL;
33 extern BOOL CanRecurse;
35 extern struct in_addr ipzero;
37 extern pstring myname;
39 extern int ClientDGRAM;
42 /* this is our domain/workgroup/server database */
43 extern struct subnet_record *subnetlist;
45 /* machine comment for host announcements */
46 extern pstring ServerComment;
48 extern int updatecount;
49 extern int workgroup_count;
51 /* what server type are we currently */
53 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
55 /****************************************************************************
56 send a announce request to the local net
57 **************************************************************************/
58 void announce_request(struct work_record *work, struct in_addr ip)
65 work->needannounce = True;
67 DEBUG(2,("sending announce request to %s for workgroup %s\n",
68 inet_ntoa(ip),work->work_group));
70 bzero(outbuf,sizeof(outbuf));
72 CVAL(p,0) = ANN_AnnouncementRequest;
75 CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
81 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
82 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
86 /****************************************************************************
87 request an announcement
88 **************************************************************************/
89 void do_announce_request(char *info, char *to_name, int announce_type,
91 int to, struct in_addr dest_ip)
96 bzero(outbuf,sizeof(outbuf));
98 CVAL(p,0) = announce_type;
101 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
102 announce_type, info, inet_ntoa(dest_ip),to_name,to));
106 p = skip_string(p,1);
108 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
109 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
112 /****************************************************************************
113 construct a host announcement unicast
114 **************************************************************************/
115 void announce_backup(void)
117 static time_t lastrun = 0;
118 time_t t = time(NULL);
121 struct subnet_record *d1;
124 if (!lastrun) lastrun = t;
125 if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60) return;
128 for (tok = 0; tok <= workgroup_count; tok++)
130 for (d1 = subnetlist; d1; d1 = d1->next)
132 struct work_record *work;
133 struct subnet_record *d;
135 /* search for unique workgroup: only the name matters */
136 for (work = d1->workgrouplist;
137 work && (tok != work->token);
142 /* found one: announce it across all domains */
143 for (d = subnetlist; d; d = d->next)
147 if (AM_DOMCTL(work)) {
149 } else if (AM_MASTER(work)) {
155 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
156 inet_ntoa(d->bcast_ip),work->work_group,
159 bzero(outbuf,sizeof(outbuf));
161 CVAL(p,0) = ANN_GetBackupListReq;
164 CVAL(p,0) = 1; /* count? */
165 SIVAL(p,1,work->token); /* workgroup unique key index */
169 send_mailslot_reply(BROWSE_MAILSLOT,
172 myname, work->work_group,
173 0x0,type,d->bcast_ip,
174 *iface_ip(d->bcast_ip));
181 /****************************************************************************
182 construct a host announcement unicast
183 **************************************************************************/
184 void announce_host(void)
186 time_t t = time(NULL);
194 struct subnet_record *d;
196 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
198 my_name = *myname ? myname : "NoName";
200 for (d = subnetlist; d; d = d->next)
202 struct work_record *work;
204 if (!d->my_interface)
207 for (work = d->workgrouplist; work; work = work->next)
209 uint32 stype = work->ServerType;
210 struct server_record *s;
211 BOOL announce = False;
213 if (work->needannounce) {
214 /* drop back to a max 3 minute announce - this is to prevent a
215 single lost packet from stuffing things up for too long */
216 work->announce_interval = MIN(work->announce_interval,
217 CHECK_TIME_MIN_HOST_ANNCE*60);
218 work->lastannounce_time = t - (work->announce_interval+1);
221 /* announce every minute at first then progress to every 12 mins */
222 if (work->lastannounce_time &&
223 (t - work->lastannounce_time) < work->announce_interval)
226 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
227 work->announce_interval += 60;
229 work->lastannounce_time = t;
231 if (!d->my_interface) {
232 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
233 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
234 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
237 for (s = work->serverlist; s; s = s->next) {
238 if (strequal(myname, s->serv.name)) {
246 bzero(outbuf,sizeof(outbuf));
249 CVAL(p,0) = updatecount;
250 /* ms - despite the spec */
251 SIVAL(p,1,work->announce_interval*1000);
253 StrnCpy(namep,my_name,16);
255 CVAL(p,21) = 2; /* major version */
256 CVAL(p,22) = 2; /* minor version */
259 SSVAL(p,27,0xaa55); /* browse signature */
260 SSVAL(p,29,1); /* browse version */
262 strcpy(commentp,comment);
264 p = skip_string(p,1);
270 SIVAL(stypep,0,work->ServerType);
272 DEBUG(2,("sending local master announce to %s for %s\n",
273 inet_ntoa(d->bcast_ip),work->work_group));
275 CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
277 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
279 my_name,work->work_group,0,
281 *iface_ip(d->bcast_ip));
283 DEBUG(2,("sending domain announce to %s for %s\n",
284 inet_ntoa(d->bcast_ip),work->work_group));
286 CVAL(outbuf,0) = ANN_DomainAnnouncement;
288 StrnCpy(namep,work->work_group,15);
290 StrnCpy(commentp,myname,15);
293 SIVAL(stypep,0,(unsigned)0x80000000);
294 p = commentp + strlen(commentp) + 1;
296 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
298 my_name,MSBROWSE,0,0x01,d->bcast_ip,
299 *iface_ip(d->bcast_ip));
303 DEBUG(2,("sending host announce to %s for %s\n",
304 inet_ntoa(d->bcast_ip),work->work_group));
306 CVAL(outbuf,0) = ANN_HostAnnouncement;
308 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
310 my_name,work->work_group,0,0x1d,
311 d->bcast_ip,*iface_ip(d->bcast_ip));
316 if (work->needannounce)
318 work->needannounce = False;
320 /* sorry: can't do too many announces. do some more later */
327 /****************************************************************************
328 announce myself as a master to all other primary domain conrollers.
330 BIG NOTE: this code will remain untested until some kind soul that has access
331 to a couple of windows NT advanced servers runs this version of nmbd for at
334 this actually gets done in search_and_sync_workgroups() via the
335 MASTER_SERVER_CHECK command, if there is a response from the
336 name query initiated here. see response_name_query()
337 **************************************************************************/
338 void announce_master(void)
340 struct subnet_record *d;
341 static time_t last=0;
342 time_t t = time(NULL);
343 BOOL am_master = False; /* are we a master of some sort? :-) */
345 if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60))
350 for (d = subnetlist; d; d = d->next)
352 struct work_record *work;
353 for (work = d->workgrouplist; work; work = work->next)
362 if (!am_master) return; /* only proceed if we are a master browser */
364 for (d = subnetlist; d; d = d->next)
366 struct work_record *work;
367 for (work = d->workgrouplist; work; work = work->next)
369 struct server_record *s;
370 for (s = work->serverlist; s; s = s->next)
372 if (strequal(s->serv.name, myname)) continue;
374 /* all PDCs (which should also be master browsers) */
375 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
377 /* check the existence of a pdc for this workgroup, and if
378 one exists at the specified ip, sync with it and announce
379 ourselves as a master browser to it */
381 if (!*lp_domain_controller() ||
382 !strequal(lp_domain_controller(), s->serv.name))
384 if (!lp_wins_support() && *lp_wins_server())
389 queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
391 work->work_group,0x1b,0,
396 struct subnet_record *d2;
397 for (d2 = subnetlist; d2; d2 = d2->next)
399 queue_netbios_packet(ClientNMB,NMB_QUERY,
401 work->work_group,0x1b,0,
402 True, False, d2->bcast_ip);
409 /* now do primary domain controller - the one that's not
410 necessarily in our browse lists, although it ought to be
411 this pdc is the one that we get TOLD about through smb.conf.
412 basically, if it's on a subnet that we know about, it may end
413 up in our browse lists (which is why it's explicitly excluded
414 in the code above) */
416 if (*lp_domain_controller())
421 ip = *interpret_addr2(lp_domain_controller());
428 DEBUG(2, ("Searching for PDC %s at %s\n",
429 lp_domain_controller(), inet_ntoa(ip)));
431 /* check the existence of a pdc for this workgroup, and if
432 one exists at the specified ip, sync with it and announce
433 ourselves as a master browser to it */
434 queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
435 work->work_group,0x1b, 0,