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 for (work = d->workgrouplist; work; work = work->next)
206 uint32 stype = work->ServerType;
207 struct server_record *s;
208 BOOL announce = False;
210 if (work->needannounce) {
211 /* drop back to a max 3 minute announce - this is to prevent a
212 single lost packet from stuffing things up for too long */
213 work->announce_interval = MIN(work->announce_interval,
214 CHECK_TIME_MIN_HOST_ANNCE*60);
215 work->lastannounce_time = t - (work->announce_interval+1);
218 /* announce every minute at first then progress to every 12 mins */
219 if (work->lastannounce_time &&
220 (t - work->lastannounce_time) < work->announce_interval)
223 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
224 work->announce_interval += 60;
226 work->lastannounce_time = t;
228 /* when announcing to remote networks we make sure we don't
229 claim to be any sort of special server, otherwise we may
230 stuff up their browsing */
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);
266 if (d->my_interface && AM_MASTER(work))
268 SIVAL(stypep,0,work->ServerType);
270 DEBUG(2,("sending local master announce to %s for %s\n",
271 inet_ntoa(d->bcast_ip),work->work_group));
273 CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
275 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
277 my_name,work->work_group,0,
279 *iface_ip(d->bcast_ip));
281 DEBUG(2,("sending domain announce to %s for %s\n",
282 inet_ntoa(d->bcast_ip),work->work_group));
284 CVAL(outbuf,0) = ANN_DomainAnnouncement;
286 StrnCpy(namep,work->work_group,15);
288 StrnCpy(commentp,myname,15);
291 SIVAL(stypep,0,(unsigned)0x80000000);
292 p = commentp + strlen(commentp) + 1;
294 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
296 my_name,MSBROWSE,0,0x01,d->bcast_ip,
297 *iface_ip(d->bcast_ip));
301 DEBUG(2,("sending host announce to %s for %s\n",
302 inet_ntoa(d->bcast_ip),work->work_group));
304 CVAL(outbuf,0) = ANN_HostAnnouncement;
306 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
308 my_name,work->work_group,0,0x1d,
309 d->bcast_ip,*iface_ip(d->bcast_ip));
313 if (work->needannounce) {
314 work->needannounce = False;
316 /* sorry: can't do too many announces. do some more later */
323 /****************************************************************************
324 announce myself as a master to all other primary domain conrollers.
326 BIG NOTE: this code will remain untested until some kind soul that has access
327 to a couple of windows NT advanced servers runs this version of nmbd for at
330 this actually gets done in search_and_sync_workgroups() via the
331 MASTER_SERVER_CHECK command, if there is a response from the
332 name query initiated here. see response_name_query()
333 **************************************************************************/
334 void announce_master(void)
336 struct subnet_record *d;
337 static time_t last=0;
338 time_t t = time(NULL);
339 BOOL am_master = False; /* are we a master of some sort? :-) */
341 if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60))
346 for (d = subnetlist; d; d = d->next)
348 struct work_record *work;
349 for (work = d->workgrouplist; work; work = work->next)
358 if (!am_master) return; /* only proceed if we are a master browser */
360 for (d = subnetlist; d; d = d->next)
362 struct work_record *work;
363 for (work = d->workgrouplist; work; work = work->next)
365 struct server_record *s;
366 for (s = work->serverlist; s; s = s->next)
368 if (strequal(s->serv.name, myname)) continue;
370 /* all PDCs (which should also be master browsers) */
371 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
373 /* check the existence of a pdc for this workgroup, and if
374 one exists at the specified ip, sync with it and announce
375 ourselves as a master browser to it */
377 if (!*lp_domain_controller() ||
378 !strequal(lp_domain_controller(), s->serv.name))
380 if (!lp_wins_support() && *lp_wins_server())
385 queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
387 work->work_group,0x1b,0,
392 struct subnet_record *d2;
393 for (d2 = subnetlist; d2; d2 = d2->next)
395 queue_netbios_packet(ClientNMB,NMB_QUERY,
397 work->work_group,0x1b,0,
398 True, False, d2->bcast_ip);
405 /* now do primary domain controller - the one that's not
406 necessarily in our browse lists, although it ought to be
407 this pdc is the one that we get TOLD about through smb.conf.
408 basically, if it's on a subnet that we know about, it may end
409 up in our browse lists (which is why it's explicitly excluded
410 in the code above) */
412 if (*lp_domain_controller())
417 ip = *interpret_addr2(lp_domain_controller());
424 DEBUG(2, ("Searching for PDC %s at %s\n",
425 lp_domain_controller(), inet_ntoa(ip)));
427 /* check the existence of a pdc for this workgroup, and if
428 one exists at the specified ip, sync with it and announce
429 ourselves as a master browser to it */
430 queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
431 work->work_group,0x1b, 0,