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;
397 if (!d->my_interface) {
398 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
399 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
400 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
403 for (s = work->serverlist; s; s = s->next) {
404 if (strequal(myname, s->serv.name)) {
412 announce_server(d,work,my_name,comment,work->announce_interval,stype);
415 if (work->needannounce)
417 work->needannounce = False;
419 /* sorry: can't do too many announces. do some more later */
426 /****************************************************************************
427 announce myself as a master to all other primary domain conrollers.
429 BIG NOTE: this code will remain untested until some kind soul that has access
430 to a couple of windows NT advanced servers runs this version of nmbd for at
433 this actually gets done in search_and_sync_workgroups() via the
434 NAME_QUERY_PDC_SRV_CHK command, if there is a response from the
435 name query initiated here. see response_name_query()
436 **************************************************************************/
437 void announce_master(void)
439 struct subnet_record *d;
440 static time_t last=0;
441 time_t t = time(NULL);
442 BOOL am_master = False; /* are we a master of some sort? :-) */
445 if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
450 for (d = subnetlist; d; d = d->next)
452 struct work_record *work;
453 for (work = d->workgrouplist; work; work = work->next)
462 if (!am_master) return; /* only proceed if we are a master browser */
464 for (d = subnetlist; d; d = d->next)
466 struct work_record *work;
467 for (work = d->workgrouplist; work; work = work->next)
469 struct server_record *s;
470 for (s = work->serverlist; s; s = s->next)
472 if (strequal(s->serv.name, myname)) continue;
474 /* all PDCs (which should also be master browsers) */
475 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
477 /* check the existence of a pdc for this workgroup, and if
478 one exists at the specified ip, sync with it and announce
479 ourselves as a master browser to it */
481 if (!*lp_domain_controller() ||
482 !strequal(lp_domain_controller(), s->serv.name))
484 if (!lp_wins_support() && *lp_wins_server())
489 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
490 NAME_QUERY_PDC_SRV_CHK,
491 work->work_group,0x1b,0,0,
492 False, False, ip, ip);
496 struct subnet_record *d2;
497 for (d2 = subnetlist; d2; d2 = d2->next)
499 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
500 NAME_QUERY_PDC_SRV_CHK,
501 work->work_group,0x1b,0,0,
502 True, False, d2->bcast_ip, d2->bcast_ip);
509 /* now do primary domain controller - the one that's not
510 necessarily in our browse lists, although it ought to be
511 this pdc is the one that we get TOLD about through smb.conf.
512 basically, if it's on a subnet that we know about, it may end
513 up in our browse lists (which is why it's explicitly excluded
514 in the code above) */
516 if (*lp_domain_controller())
521 ip = *interpret_addr2(lp_domain_controller());
528 DEBUG(2, ("Searching for PDC %s at %s\n",
529 lp_domain_controller(), inet_ntoa(ip)));
531 /* check the existence of a pdc for this workgroup, and if
532 one exists at the specified ip, sync with it and announce
533 ourselves as a master browser to it */
534 queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_PDC_SRV_CHK,
535 work->work_group,0x1b, 0, 0,
536 bcast, False, ip, ip);