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 myip;
37 extern struct in_addr bcast_ip;
38 extern struct in_addr Netmask;
39 extern struct in_addr ipzero;
41 extern pstring myname;
43 extern int ClientDGRAM;
46 /* this is our domain/workgroup/server database */
47 extern struct domain_record *domainlist;
49 /* machine comment for host announcements */
50 extern pstring ServerComment;
52 extern int updatecount;
53 extern int workgroup_count;
55 /* what server type are we currently */
57 #define MSBROWSE "\001\002__MSBROWSE__\002"
58 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
60 /****************************************************************************
61 send a announce request to the local net
62 **************************************************************************/
63 void announce_request(struct work_record *work, struct in_addr ip)
70 work->needannounce = True;
72 DEBUG(2,("sending announce request to %s for workgroup %s\n",
73 inet_ntoa(ip),work->work_group));
75 bzero(outbuf,sizeof(outbuf));
77 CVAL(p,0) = ANN_AnnouncementRequest;
80 CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
86 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
87 myname,work->work_group,0x20,0x0,ip,myip);
91 /****************************************************************************
92 request an announcement
93 **************************************************************************/
94 void do_announce_request(char *info, char *to_name, int announce_type,
96 int to, struct in_addr dest_ip)
101 bzero(outbuf,sizeof(outbuf));
103 CVAL(p,0) = announce_type;
106 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
107 announce_type, info, inet_ntoa(dest_ip),to_name,to));
111 p = skip_string(p,1);
113 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
114 myname,to_name,from,to,dest_ip,myip);
117 /****************************************************************************
118 construct a host announcement unicast
119 **************************************************************************/
120 void announce_backup(void)
122 static time_t lastrun = 0;
123 time_t t = time(NULL);
126 struct domain_record *d1;
129 if (!lastrun) lastrun = t;
130 if (t < lastrun + 1*60) return;
133 for (tok = 0; tok <= workgroup_count; tok++)
135 for (d1 = domainlist; d1; d1 = d1->next)
137 struct work_record *work;
138 struct domain_record *d;
140 /* search for unique workgroup: only the name matters */
141 for (work = d1->workgrouplist;
142 work && (tok != work->token);
147 /* found one: announce it across all domains */
148 for (d = domainlist; d; d = d->next)
152 if (AM_DOMCTL(work)) {
154 } else if (AM_MASTER(work)) {
160 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
161 inet_ntoa(d->bcast_ip),work->work_group,
164 bzero(outbuf,sizeof(outbuf));
166 CVAL(p,0) = ANN_GetBackupListReq;
169 CVAL(p,0) = 1; /* count? */
170 SIVAL(p,1,work->token); /* workgroup unique key index */
174 send_mailslot_reply(BROWSE_MAILSLOT,
177 myname, work->work_group,
178 0x0,type,d->bcast_ip,myip);
185 /****************************************************************************
186 construct a host announcement unicast
187 **************************************************************************/
188 void announce_host(void)
190 time_t t = time(NULL);
198 struct domain_record *d;
200 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
202 my_name = *myname ? myname : "NoName";
204 for (d = domainlist; d; d = d->next)
206 struct work_record *work;
208 if (!ip_equal(bcast_ip,d->bcast_ip))
211 for (work = d->workgrouplist; work; work = work->next)
213 uint32 stype = work->ServerType;
214 struct server_record *s;
215 BOOL announce = False;
217 if (work->needannounce) {
218 /* drop back to a max 3 minute announce - this is to prevent a
219 single lost packet from stuffing things up for too long */
220 work->announce_interval = MIN(work->announce_interval,3*60);
221 work->lastannounce_time = t - (work->announce_interval+1);
224 /* announce every minute at first then progress to every 12 mins */
225 if (work->lastannounce_time &&
226 (t - work->lastannounce_time) < work->announce_interval)
229 if (work->announce_interval < 12*60)
230 work->announce_interval += 60;
232 work->lastannounce_time = t;
234 if (!ip_equal(bcast_ip,d->bcast_ip)) {
235 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
236 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
237 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
240 for (s = work->serverlist; s; s = s->next) {
241 if (strequal(myname, s->serv.name)) {
249 bzero(outbuf,sizeof(outbuf));
252 CVAL(p,0) = updatecount;
253 /* ms - despite the spec */
254 SIVAL(p,1,work->announce_interval*1000);
256 StrnCpy(namep,my_name,16);
258 CVAL(p,21) = 2; /* major version */
259 CVAL(p,22) = 2; /* minor version */
262 SSVAL(p,27,0xaa55); /* browse signature */
263 SSVAL(p,29,1); /* browse version */
265 strcpy(commentp,comment);
267 p = skip_string(p,1);
269 if (ip_equal(bcast_ip,d->bcast_ip))
273 SIVAL(stypep,0,work->ServerType);
275 DEBUG(2,("sending local master announce to %s for %s\n",
276 inet_ntoa(d->bcast_ip),work->work_group));
278 CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
280 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
282 my_name,work->work_group,0,
283 0x1e,d->bcast_ip,myip);
285 DEBUG(2,("sending domain announce to %s for %s\n",
286 inet_ntoa(d->bcast_ip),work->work_group));
288 CVAL(outbuf,0) = ANN_DomainAnnouncement;
290 StrnCpy(namep,work->work_group,15);
292 StrnCpy(commentp,myname,15);
295 SIVAL(stypep,0,(unsigned)0x80000000);
296 p = commentp + strlen(commentp) + 1;
298 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
300 my_name,MSBROWSE,0,0x01,d->bcast_ip,myip);
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,
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 domain_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? :-) */
347 if (last && (t-last < 2*60)) return;
349 if (last && (t-last < 15*60)) return;
354 for (d = domainlist; d; d = d->next)
356 struct work_record *work;
357 for (work = d->workgrouplist; work; work = work->next)
366 if (!am_master) return; /* only proceed if we are a master browser */
368 for (d = domainlist; d; d = d->next)
370 struct work_record *work;
371 for (work = d->workgrouplist; work; work = work->next)
373 struct server_record *s;
374 for (s = work->serverlist; s; s = s->next)
376 if (strequal(s->serv.name, myname)) continue;
378 /* all PDCs (which should also be master browsers) */
379 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
381 /* check the existence of a pdc for this workgroup, and if
382 one exists at the specified ip, sync with it and announce
383 ourselves as a master browser to it */
385 if (!*lp_domain_controller() ||
386 !strequal(lp_domain_controller(), s->serv.name))
388 if (!lp_wins_support() && *lp_wins_server())
393 queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
395 work->work_group,0x1b,0,
400 struct domain_record *d2;
401 for (d2 = domainlist; d2; d2 = d2->next)
403 queue_netbios_packet(ClientNMB,NMB_QUERY,
405 work->work_group,0x1b,0,
406 True, False, d2->bcast_ip);
413 /* now do primary domain controller - the one that's not
414 necessarily in our browse lists, although it ought to be
415 this pdc is the one that we get TOLD about through smb.conf.
416 basically, if it's on a subnet that we know about, it may end
417 up in our browse lists (which is why it's explicitly excluded
418 in the code above) */
420 if (*lp_domain_controller())
425 ip = *interpret_addr2(lp_domain_controller());
433 DEBUG(2, ("Searching for PDC %s at %s\n",
434 lp_domain_controller(), inet_ntoa(ip)));
436 /* check the existence of a pdc for this workgroup, and if
437 one exists at the specified ip, sync with it and announce
438 ourselves as a master browser to it */
439 queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
440 work->work_group,0x1b, 0,