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
33 extern int DEBUGLEVEL;
34 extern BOOL CanRecurse;
36 extern struct in_addr ipzero;
38 extern pstring myname;
40 extern int ClientDGRAM;
43 /* this is our domain/workgroup/server database */
44 extern struct subnet_record *subnetlist;
46 /* machine comment for host announcements */
47 extern pstring ServerComment;
49 extern int updatecount;
50 extern int workgroup_count;
52 /* what server type are we currently */
54 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
56 /****************************************************************************
57 send a announce request to the local net
58 **************************************************************************/
59 void announce_request(struct work_record *work, struct in_addr ip)
66 work->needannounce = True;
68 DEBUG(2,("sending announce request to %s for workgroup %s\n",
69 inet_ntoa(ip),work->work_group));
71 bzero(outbuf,sizeof(outbuf));
73 CVAL(p,0) = ANN_AnnouncementRequest;
76 CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
82 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
83 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
87 /****************************************************************************
88 request an announcement
89 **************************************************************************/
90 void do_announce_request(char *info, char *to_name, int announce_type,
92 int to, struct in_addr dest_ip)
97 bzero(outbuf,sizeof(outbuf));
99 CVAL(p,0) = announce_type;
102 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
103 announce_type, info, inet_ntoa(dest_ip),to_name,to));
107 p = skip_string(p,1);
109 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
110 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
113 /****************************************************************************
114 construct a host announcement unicast
115 **************************************************************************/
116 void announce_backup(void)
118 static time_t lastrun = 0;
119 time_t t = time(NULL);
122 struct subnet_record *d1;
125 if (!lastrun) lastrun = t;
126 if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60) return;
129 for (tok = 0; tok <= workgroup_count; tok++)
131 for (d1 = subnetlist; d1; d1 = d1->next)
133 struct work_record *work;
134 struct subnet_record *d;
136 /* search for unique workgroup: only the name matters */
137 for (work = d1->workgrouplist;
138 work && (tok != work->token);
143 /* found one: announce it across all domains */
144 for (d = subnetlist; d; d = d->next)
148 if (AM_DOMCTL(work)) {
150 } else if (AM_MASTER(work)) {
156 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
157 inet_ntoa(d->bcast_ip),work->work_group,
160 bzero(outbuf,sizeof(outbuf));
162 CVAL(p,0) = ANN_GetBackupListReq;
165 CVAL(p,0) = 1; /* count? */
166 SIVAL(p,1,work->token); /* workgroup unique key index */
170 send_mailslot_reply(BROWSE_MAILSLOT,
173 myname, work->work_group,
174 0x0,type,d->bcast_ip,
175 *iface_ip(d->bcast_ip));
182 /****************************************************************************
183 construct a host announcement unicast
184 **************************************************************************/
185 void announce_host(void)
187 time_t t = time(NULL);
195 struct subnet_record *d;
197 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
199 my_name = *myname ? myname : "NoName";
201 for (d = subnetlist; d; d = d->next)
203 struct work_record *work;
205 if (!d->my_interface)
208 for (work = d->workgrouplist; work; work = work->next)
210 uint32 stype = work->ServerType;
211 struct server_record *s;
212 BOOL announce = False;
214 if (work->needannounce) {
215 /* drop back to a max 3 minute announce - this is to prevent a
216 single lost packet from stuffing things up for too long */
217 work->announce_interval = MIN(work->announce_interval,
218 CHECK_TIME_MIN_HOST_ANNCE*60);
219 work->lastannounce_time = t - (work->announce_interval+1);
222 /* announce every minute at first then progress to every 12 mins */
223 if (work->lastannounce_time &&
224 (t - work->lastannounce_time) < work->announce_interval)
227 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
228 work->announce_interval += 60;
230 work->lastannounce_time = t;
232 if (!d->my_interface) {
233 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
234 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
235 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
238 for (s = work->serverlist; s; s = s->next) {
239 if (strequal(myname, s->serv.name)) {
247 bzero(outbuf,sizeof(outbuf));
250 CVAL(p,0) = updatecount;
251 /* ms - despite the spec */
252 SIVAL(p,1,work->announce_interval*1000);
254 StrnCpy(namep,my_name,16);
256 CVAL(p,21) = 2; /* major version */
257 CVAL(p,22) = 2; /* minor version */
260 SSVAL(p,27,0xaa55); /* browse signature */
261 SSVAL(p,29,1); /* browse version */
263 strcpy(commentp,comment);
265 p = skip_string(p,1);
271 SIVAL(stypep,0,work->ServerType);
273 DEBUG(2,("sending local master announce to %s for %s\n",
274 inet_ntoa(d->bcast_ip),work->work_group));
276 CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
278 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
280 my_name,work->work_group,0,
282 *iface_ip(d->bcast_ip));
284 DEBUG(2,("sending domain announce to %s for %s\n",
285 inet_ntoa(d->bcast_ip),work->work_group));
287 CVAL(outbuf,0) = ANN_DomainAnnouncement;
289 StrnCpy(namep,work->work_group,15);
291 StrnCpy(commentp,myname,15);
294 SIVAL(stypep,0,(unsigned)0x80000000);
295 p = commentp + strlen(commentp) + 1;
297 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
299 my_name,MSBROWSE,0,0x01,d->bcast_ip,
300 *iface_ip(d->bcast_ip));
304 DEBUG(2,("sending host announce to %s for %s\n",
305 inet_ntoa(d->bcast_ip),work->work_group));
307 CVAL(outbuf,0) = ANN_HostAnnouncement;
309 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
311 my_name,work->work_group,0,0x1d,
312 d->bcast_ip,*iface_ip(d->bcast_ip));
317 if (work->needannounce)
319 work->needannounce = False;
321 /* sorry: can't do too many announces. do some more later */
328 /****************************************************************************
329 announce myself as a master to all other primary domain conrollers.
331 BIG NOTE: this code will remain untested until some kind soul that has access
332 to a couple of windows NT advanced servers runs this version of nmbd for at
335 this actually gets done in search_and_sync_workgroups() via the
336 MASTER_SERVER_CHECK command, if there is a response from the
337 name query initiated here. see response_name_query()
338 **************************************************************************/
339 void announce_master(void)
341 struct subnet_record *d;
342 static time_t last=0;
343 time_t t = time(NULL);
344 BOOL am_master = False; /* are we a master of some sort? :-) */
346 if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60))
351 for (d = subnetlist; d; d = d->next)
353 struct work_record *work;
354 for (work = d->workgrouplist; work; work = work->next)
363 if (!am_master) return; /* only proceed if we are a master browser */
365 for (d = subnetlist; d; d = d->next)
367 struct work_record *work;
368 for (work = d->workgrouplist; work; work = work->next)
370 struct server_record *s;
371 for (s = work->serverlist; s; s = s->next)
373 if (strequal(s->serv.name, myname)) continue;
375 /* all PDCs (which should also be master browsers) */
376 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
378 /* check the existence of a pdc for this workgroup, and if
379 one exists at the specified ip, sync with it and announce
380 ourselves as a master browser to it */
382 if (!*lp_domain_controller() ||
383 !strequal(lp_domain_controller(), s->serv.name))
385 if (!lp_wins_support() && *lp_wins_server())
390 queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
392 work->work_group,0x1b,0,
397 struct subnet_record *d2;
398 for (d2 = subnetlist; d2; d2 = d2->next)
400 queue_netbios_packet(ClientNMB,NMB_QUERY,
402 work->work_group,0x1b,0,
403 True, False, d2->bcast_ip);
410 /* now do primary domain controller - the one that's not
411 necessarily in our browse lists, although it ought to be
412 this pdc is the one that we get TOLD about through smb.conf.
413 basically, if it's on a subnet that we know about, it may end
414 up in our browse lists (which is why it's explicitly excluded
415 in the code above) */
417 if (*lp_domain_controller())
422 ip = *interpret_addr2(lp_domain_controller());
429 DEBUG(2, ("Searching for PDC %s at %s\n",
430 lp_domain_controller(), inet_ntoa(ip)));
432 /* check the existence of a pdc for this workgroup, and if
433 one exists at the specified ip, sync with it and announce
434 ourselves as a master browser to it */
435 queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
436 work->work_group,0x1b, 0,