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 extern struct in_addr ipgrp;
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; /* (local) unique workgroup token id */
79 /* XXXX note: if we sent the announcement request to 0x1d instead
80 of 0x1e, then we could get the master browser to announce to
81 us instead of the members of the workgroup. wha-hey! */
83 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
84 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
88 /****************************************************************************
89 request an announcement
90 **************************************************************************/
91 void do_announce_request(char *info, char *to_name, int announce_type,
93 int to, struct in_addr dest_ip)
98 bzero(outbuf,sizeof(outbuf));
100 CVAL(p,0) = announce_type;
103 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
104 announce_type, info, inet_ntoa(dest_ip),to_name,to));
108 p = skip_string(p,1);
110 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
111 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
115 /****************************************************************************
116 find a server responsible for a workgroup, and sync browse lists
117 control ends up back here via response_name_query.
118 **************************************************************************/
119 void sync_server(enum state_type state, char *serv_name, char *work_name,
123 add_browser_entry(serv_name, name_type, work_name, 0, ip);
125 if (state == NAME_STATUS_PDC_SRV_CHK)
127 /* announce ourselves as a master browser to serv_name */
128 do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
134 /****************************************************************************
135 construct a host announcement unicast
137 this function should not be used heavily, and only when we are _not_
138 a master browser and _not_ a primary domain controller.
140 **************************************************************************/
141 void announce_backup(void)
143 static time_t lastrun = 0;
144 time_t t = time(NULL);
147 struct subnet_record *d1;
149 static uint32 id_count = 0;
151 if (!lastrun) lastrun = t;
153 if (t < lastrun + 1 * 60)
155 if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
160 DEBUG(4,("checking backups...\n"));
162 for (tok = 0; tok <= workgroup_count; tok++)
164 for (d1 = subnetlist; d1; d1 = d1->next)
166 struct work_record *work;
167 struct subnet_record *d;
169 /* search for unique workgroup: only the name matters */
170 for (work = d1->workgrouplist;
171 work && (tok != work->token);
176 if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
178 /* found one: announce it across all domains */
179 for (d = subnetlist; d; d = d->next)
182 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
183 inet_ntoa(d->bcast_ip),work->work_group,
186 bzero(outbuf,sizeof(outbuf));
189 CVAL(p,0) = ANN_GetBackupListReq;
190 CVAL(p,1) = work->token; /* workgroup unique key index */
191 SIVAL(p,2,++id_count); /* unique count. not that we use it! */
195 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
197 if (!AM_DOMCTL(work))
199 /* only ask for a list of backup domain controllers
200 if we are not a domain controller ourselves */
202 send_mailslot_reply(BROWSE_MAILSLOT,
205 myname, work->work_group,
206 0x0,0x1b,d->bcast_ip,
207 *iface_ip(d->bcast_ip));
210 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
212 if (!AM_MASTER(work))
214 /* only ask for a list of master browsers if we
215 are not a master browser ourselves */
217 send_mailslot_reply(BROWSE_MAILSLOT,
220 myname, work->work_group,
221 0x0,0x1d,d->bcast_ip,
222 *iface_ip(d->bcast_ip));
230 /****************************************************************************
231 send a host announcement packet
232 **************************************************************************/
233 static void do_announce_host(int command,
234 char *from_name, int from_type, struct in_addr from_ip,
235 char *to_name , int to_type , struct in_addr to_ip,
236 time_t announce_interval,
237 char *server_name, int server_type, char *server_comment)
242 bzero(outbuf,sizeof(outbuf));
246 CVAL(outbuf,0) = command;
248 /* announcement parameters */
249 CVAL(p,0) = updatecount;
250 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
252 StrnCpy(p+5,server_name,16);
255 CVAL(p,21) = 0x02; /* major version */
256 CVAL(p,22) = 0x02; /* minor version */
258 SIVAL(p,23,server_type);
259 SSVAL(p,27,0x010f); /* browse version: got from NT/AS 4.00 */
260 SSVAL(p,29,0xaa55); /* browse signature */
262 strcpy(p+31,server_comment);
264 p = skip_string(p,1);
266 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
268 /* send the announcement */
269 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
277 /****************************************************************************
278 remove all samba's server entries
279 ****************************************************************************/
280 void remove_my_servers(void)
282 struct subnet_record *d;
283 for (d = subnetlist; d; d = d->next)
285 struct work_record *work;
286 for (work = d->workgrouplist; work; work = work->next)
288 struct server_record *s;
289 for (s = work->serverlist; s; s = s->next)
291 if (!strequal(myname,s->serv.name)) continue;
292 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
299 /****************************************************************************
300 announce a server entry
301 ****************************************************************************/
302 void announce_server(struct subnet_record *d, struct work_record *work,
303 char *name, char *comment, time_t ttl, int server_type)
305 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX;
309 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
310 inet_ntoa(d->bcast_ip),work->work_group));
312 do_announce_host(ANN_LocalMasterAnnouncement,
313 name , 0x00, d->myip,
314 work->work_group, 0x1e, d->bcast_ip,
316 name, server_type, comment);
318 DEBUG(3,("sending domain announce to %s for %s\n",
319 inet_ntoa(d->bcast_ip),work->work_group));
321 /* XXXX should we do a domain-announce-kill? */
322 if (server_type != 0)
324 if (AM_DOMCTL(work)) {
325 domain_type |= SV_TYPE_DOMAIN_CTRL;
327 do_announce_host(ANN_DomainAnnouncement,
328 name , 0x00, d->myip,
329 MSBROWSE, 0x01, d->bcast_ip,
331 work->work_group, server_type ? domain_type : 0,
337 DEBUG(3,("sending host announce to %s for %s(1d)\n",
338 inet_ntoa(d->bcast_ip),work->work_group));
340 do_announce_host(ANN_HostAnnouncement,
341 name , 0x00, d->myip,
342 work->work_group, 0x1d, d->bcast_ip,
344 name, server_type, comment);
348 /****************************************************************************
349 construct a host announcement unicast
350 **************************************************************************/
351 void announce_host(void)
353 time_t t = time(NULL);
354 struct subnet_record *d;
358 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
360 my_name = *myname ? myname : "NoName";
362 for (d = subnetlist; d; d = d->next)
364 struct work_record *work;
366 if (ip_equal(d->bcast_ip, ipgrp)) continue;
368 for (work = d->workgrouplist; work; work = work->next)
370 uint32 stype = work->ServerType;
371 struct server_record *s;
372 BOOL announce = False;
374 /* must work on the code that does announcements at up to
375 30 seconds later if a master browser sends us a request
379 if (work->needannounce) {
380 /* drop back to a max 3 minute announce - this is to prevent a
381 single lost packet from stuffing things up for too long */
382 work->announce_interval = MIN(work->announce_interval,
383 CHECK_TIME_MIN_HOST_ANNCE*60);
384 work->lastannounce_time = t - (work->announce_interval+1);
387 /* announce every minute at first then progress to every 12 mins */
388 if (work->lastannounce_time &&
389 (t - work->lastannounce_time) < work->announce_interval)
392 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
393 work->announce_interval += 60;
395 work->lastannounce_time = t;
398 if (!d->my_interface) {
399 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
400 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
401 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
405 for (s = work->serverlist; s; s = s->next) {
406 if (strequal(myname, s->serv.name)) {
414 announce_server(d,work,my_name,comment,work->announce_interval,stype);
417 if (work->needannounce)
419 work->needannounce = False;
421 /* sorry: can't do too many announces. do some more later */
428 /****************************************************************************
429 announce myself as a master to all other primary domain conrollers.
431 BIG NOTE: this code will remain untested until some kind soul that has access
432 to a couple of windows NT advanced servers runs this version of nmbd for at
435 this actually gets done in search_and_sync_workgroups() via the
436 NAME_QUERY_PDC_SRV_CHK command, if there is a response from the
437 name query initiated here. see response_name_query()
438 **************************************************************************/
439 void announce_master(void)
441 struct subnet_record *d;
442 static time_t last=0;
443 time_t t = time(NULL);
444 BOOL am_master = False; /* are we a master of some sort? :-) */
447 if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
452 for (d = subnetlist; d; d = d->next)
454 struct work_record *work;
455 for (work = d->workgrouplist; work; work = work->next)
464 if (!am_master) return; /* only proceed if we are a master browser */
466 for (d = subnetlist; d; d = d->next)
468 struct work_record *work;
469 for (work = d->workgrouplist; work; work = work->next)
471 struct server_record *s;
472 for (s = work->serverlist; s; s = s->next)
474 if (strequal(s->serv.name, myname)) continue;
476 /* all PDCs (which should also be master browsers) */
477 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
479 /* check the existence of a pdc for this workgroup, and if
480 one exists at the specified ip, sync with it and announce
481 ourselves as a master browser to it */
483 if (!*lp_domain_controller() ||
484 !strequal(lp_domain_controller(), s->serv.name))
486 if (!lp_wins_support() && *lp_wins_server())
491 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
492 NAME_QUERY_PDC_SRV_CHK,
493 work->work_group,0x1b,0,0,
494 False, False, ip, ip);
498 struct subnet_record *d2;
499 for (d2 = subnetlist; d2; d2 = d2->next)
501 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
502 NAME_QUERY_PDC_SRV_CHK,
503 work->work_group,0x1b,0,0,
504 True, False, d2->bcast_ip, d2->bcast_ip);
511 /* now do primary domain controller - the one that's not
512 necessarily in our browse lists, although it ought to be
513 this pdc is the one that we get TOLD about through smb.conf.
514 basically, if it's on a subnet that we know about, it may end
515 up in our browse lists (which is why it's explicitly excluded
516 in the code above) */
518 if (*lp_domain_controller())
523 ip = *interpret_addr2(lp_domain_controller());
530 DEBUG(2, ("Searching for PDC %s at %s\n",
531 lp_domain_controller(), inet_ntoa(ip)));
533 /* check the existence of a pdc for this workgroup, and if
534 one exists at the specified ip, sync with it and announce
535 ourselves as a master browser to it */
536 queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_PDC_SRV_CHK,
537 work->work_group,0x1b, 0, 0,
538 bcast, False, ip, ip);