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 /****************************************************************************
54 send a announce request to the local net
55 **************************************************************************/
56 void announce_request(struct work_record *work, struct in_addr ip)
63 work->needannounce = True;
65 DEBUG(2,("sending announce request to %s for workgroup %s\n",
66 inet_ntoa(ip),work->work_group));
68 bzero(outbuf,sizeof(outbuf));
70 CVAL(p,0) = ANN_AnnouncementRequest;
73 CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
79 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
80 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
84 /****************************************************************************
85 request an announcement
86 **************************************************************************/
87 void do_announce_request(char *info, char *to_name, int announce_type,
89 int to, struct in_addr dest_ip)
94 bzero(outbuf,sizeof(outbuf));
96 CVAL(p,0) = announce_type;
99 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
100 announce_type, info, inet_ntoa(dest_ip),to_name,to));
104 p = skip_string(p,1);
106 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
107 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
111 /****************************************************************************
112 find a server responsible for a workgroup, and sync browse lists
113 control ends up back here via response_name_query.
114 **************************************************************************/
115 void sync_server(enum state_type state, char *serv_name, char *work_name,
119 add_browser_entry(serv_name, name_type, work_name, 0, ip);
121 if (state == NAME_QUERY_MST_SRV_CHK)
123 /* announce ourselves as a master browser to serv_name */
124 do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
130 /****************************************************************************
131 construct a host announcement unicast
132 **************************************************************************/
133 void announce_backup(void)
135 static time_t lastrun = 0;
136 time_t t = time(NULL);
139 struct subnet_record *d1;
142 if (!lastrun) lastrun = t;
143 if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
147 for (tok = 0; tok <= workgroup_count; tok++)
149 for (d1 = subnetlist; d1; d1 = d1->next)
151 struct work_record *work;
152 struct subnet_record *d;
154 /* search for unique workgroup: only the name matters */
155 for (work = d1->workgrouplist;
156 work && (tok != work->token);
161 /* found one: announce it across all domains */
162 for (d = subnetlist; d; d = d->next)
166 if (AM_DOMCTL(work)) {
168 } else if (AM_MASTER(work)) {
174 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
175 inet_ntoa(d->bcast_ip),work->work_group,
178 bzero(outbuf,sizeof(outbuf));
180 CVAL(p,0) = ANN_GetBackupListReq;
183 CVAL(p,0) = 1; /* count? */
184 SIVAL(p,1,work->token); /* workgroup unique key index */
188 send_mailslot_reply(BROWSE_MAILSLOT,
191 myname, work->work_group,
192 0x0,type,d->bcast_ip,
193 *iface_ip(d->bcast_ip));
200 /****************************************************************************
201 send a host announcement packet
202 **************************************************************************/
203 void do_announce_host(int command,
204 char *from_name, int from_type, struct in_addr from_ip,
205 char *to_name , int to_type , struct in_addr to_ip,
206 int updatecount, time_t announce_interval,
207 char *server_name, int server_type, char *server_comment)
212 bzero(outbuf,sizeof(outbuf));
216 CVAL(outbuf,0) = command;
218 /* announcement parameters */
219 CVAL(p,0) = updatecount;
220 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
222 StrnCpy(p+5,server_name,16);
225 CVAL(p,21) = 2; /* major version */
226 CVAL(p,22) = 2; /* minor version */
228 SIVAL(p,23,server_type);
229 SSVAL(p,27,0xaa55); /* browse signature */
230 SSVAL(p,29,1); /* browse version */
232 strcpy(p+31,server_comment);
234 p = skip_string(p,1);
236 /* send the announcement */
237 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
245 /****************************************************************************
246 announce a server entry
247 ****************************************************************************/
248 void announce_server(struct subnet_record *d, struct work_record *work,
249 char *name, char *comment, time_t ttl, int server_type)
253 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
254 inet_ntoa(d->bcast_ip),work->work_group));
256 do_announce_host(ANN_LocalMasterAnnouncement,
257 name , 0x00, d->myip,
258 work->work_group, 0x1e, d->bcast_ip,
259 updatecount, ttl*1000,
260 name, server_type, comment);
262 DEBUG(3,("sending domain announce to %s for %s\n",
263 inet_ntoa(d->bcast_ip),work->work_group));
265 /* XXXX should we do a domain-announce-kill? */
266 if (server_type != 0)
268 do_announce_host(ANN_DomainAnnouncement,
269 work->work_group, 0x00, d->myip,
270 MSBROWSE , 0x01, d->bcast_ip,
271 updatecount, ttl*1000,
272 name, server_type ? SV_TYPE_DOMAIN_ENUM : 0, comment);
277 DEBUG(3,("sending host announce to %s for %s(1d)\n",
278 inet_ntoa(d->bcast_ip),work->work_group));
280 do_announce_host(ANN_HostAnnouncement,
281 name , 0x00, d->myip,
282 work->work_group, 0x1d, d->bcast_ip,
283 updatecount, ttl*1000,
284 name, server_type, comment);
288 /****************************************************************************
289 construct a host announcement unicast
290 **************************************************************************/
291 void announce_host(void)
293 time_t t = time(NULL);
294 struct subnet_record *d;
298 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
300 my_name = *myname ? myname : "NoName";
302 for (d = subnetlist; d; d = d->next)
304 struct work_record *work;
306 for (work = d->workgrouplist; work; work = work->next)
308 uint32 stype = work->ServerType;
309 struct server_record *s;
310 BOOL announce = False;
312 if (work->needannounce) {
313 /* drop back to a max 3 minute announce - this is to prevent a
314 single lost packet from stuffing things up for too long */
315 work->announce_interval = MIN(work->announce_interval,
316 CHECK_TIME_MIN_HOST_ANNCE*60);
317 work->lastannounce_time = t - (work->announce_interval+1);
320 /* announce every minute at first then progress to every 12 mins */
321 if (work->lastannounce_time &&
322 (t - work->lastannounce_time) < work->announce_interval)
325 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
326 work->announce_interval += 60;
328 work->lastannounce_time = t;
330 if (!d->my_interface) {
331 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
332 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
333 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
336 for (s = work->serverlist; s; s = s->next) {
337 if (strequal(myname, s->serv.name)) {
345 announce_server(d,work,my_name,comment,work->announce_interval,stype);
348 if (work->needannounce)
350 work->needannounce = False;
352 /* sorry: can't do too many announces. do some more later */
359 /****************************************************************************
360 announce myself as a master to all other primary domain conrollers.
362 BIG NOTE: this code will remain untested until some kind soul that has access
363 to a couple of windows NT advanced servers runs this version of nmbd for at
366 this actually gets done in search_and_sync_workgroups() via the
367 NAME_QUERY_MST_SRV_CHK command, if there is a response from the
368 name query initiated here. see response_name_query()
369 **************************************************************************/
370 void announce_master(void)
372 struct subnet_record *d;
373 static time_t last=0;
374 time_t t = time(NULL);
375 BOOL am_master = False; /* are we a master of some sort? :-) */
377 if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60))
382 for (d = subnetlist; d; d = d->next)
384 struct work_record *work;
385 for (work = d->workgrouplist; work; work = work->next)
394 if (!am_master) return; /* only proceed if we are a master browser */
396 for (d = subnetlist; d; d = d->next)
398 struct work_record *work;
399 for (work = d->workgrouplist; work; work = work->next)
401 struct server_record *s;
402 for (s = work->serverlist; s; s = s->next)
404 if (strequal(s->serv.name, myname)) continue;
406 /* all PDCs (which should also be master browsers) */
407 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
409 /* check the existence of a pdc for this workgroup, and if
410 one exists at the specified ip, sync with it and announce
411 ourselves as a master browser to it */
413 if (!*lp_domain_controller() ||
414 !strequal(lp_domain_controller(), s->serv.name))
416 if (!lp_wins_support() && *lp_wins_server())
421 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
422 NAME_QUERY_MST_SRV_CHK,
423 work->work_group,0x1b,0,0,
428 struct subnet_record *d2;
429 for (d2 = subnetlist; d2; d2 = d2->next)
431 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
432 NAME_QUERY_MST_SRV_CHK,
433 work->work_group,0x1b,0,0,
434 True, False, d2->bcast_ip);
441 /* now do primary domain controller - the one that's not
442 necessarily in our browse lists, although it ought to be
443 this pdc is the one that we get TOLD about through smb.conf.
444 basically, if it's on a subnet that we know about, it may end
445 up in our browse lists (which is why it's explicitly excluded
446 in the code above) */
448 if (*lp_domain_controller())
453 ip = *interpret_addr2(lp_domain_controller());
460 DEBUG(2, ("Searching for PDC %s at %s\n",
461 lp_domain_controller(), inet_ntoa(ip)));
463 /* check the existence of a pdc for this workgroup, and if
464 one exists at the specified ip, sync with it and announce
465 ourselves as a master browser to it */
466 queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_MST_SRV_CHK,
467 work->work_group,0x1b, 0, 0,