Removed use of 'domain controller' parameter for browsing system
[Samba/ekacnet.git] / source / nameannounce.c
blobb1d13ce7ac89bfbf9c727995164570d74b4b6a9e
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1997
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.
21 Revision History:
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
28 #include "includes.h"
30 #define TEST_CODE
32 extern int DEBUGLEVEL;
33 extern BOOL CanRecurse;
35 extern struct in_addr ipzero;
37 extern pstring myname;
38 extern fstring myworkgroup;
40 extern int ClientDGRAM;
41 extern int ClientNMB;
43 /* this is our domain/workgroup/server database */
44 extern struct subnet_record *subnetlist;
46 extern int updatecount;
47 extern int workgroup_count;
49 extern struct in_addr wins_ip;
51 extern pstring scope;
53 /****************************************************************************
54 send a announce request to the local net
55 **************************************************************************/
56 void announce_request(struct work_record *work, struct in_addr ip)
58 pstring outbuf;
59 char *p;
61 if (!work) return;
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));
69 p = outbuf;
70 CVAL(p,0) = ANN_AnnouncementRequest;
71 p++;
73 CVAL(p,0) = work->token; /* (local) unique workgroup token id */
74 p++;
75 StrnCpy(p,myname,16);
76 strupper(p);
77 p = skip_string(p,1);
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(False, BROWSE_MAILSLOT,ClientDGRAM,
84 outbuf,PTR_DIFF(p,outbuf),
85 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
89 /****************************************************************************
90 request an announcement
91 **************************************************************************/
92 void do_announce_request(char *info, char *to_name, int announce_type,
93 int from,
94 int to, struct in_addr dest_ip)
96 pstring outbuf;
97 char *p;
99 bzero(outbuf,sizeof(outbuf));
100 p = outbuf;
101 CVAL(p,0) = announce_type;
102 p++;
104 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
105 announce_type, info, inet_ntoa(dest_ip),to_name,to));
107 StrnCpy(p,info,16);
108 strupper(p);
109 p = skip_string(p,1);
111 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
112 outbuf,PTR_DIFF(p,outbuf),
113 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
117 /****************************************************************************
118 find a server responsible for a workgroup, and sync browse lists
119 control ends up back here via response_name_query.
120 **************************************************************************/
121 void sync_server(enum state_type state, char *serv_name, char *work_name,
122 int name_type,
123 struct subnet_record *d,
124 struct in_addr ip)
126 /* with a domain master we can get the whole list (not local only list) */
127 BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
129 add_browser_entry(serv_name, name_type, work_name, 0, d, ip, local_only);
131 if (state == NAME_STATUS_DOM_SRV_CHK)
133 /* announce ourselves as a master browser to serv_name */
134 do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
135 0x20, 0, ip);
140 /****************************************************************************
141 send a host announcement packet
142 **************************************************************************/
143 void do_announce_host(int command,
144 char *from_name, int from_type, struct in_addr from_ip,
145 char *to_name , int to_type , struct in_addr to_ip,
146 time_t announce_interval,
147 char *server_name, int server_type, char *server_comment)
149 pstring outbuf;
150 char *p;
152 bzero(outbuf,sizeof(outbuf));
153 p = outbuf+1;
155 /* command type */
156 CVAL(outbuf,0) = command;
158 /* announcement parameters */
159 CVAL(p,0) = updatecount;
160 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
162 StrnCpy(p+5,server_name,16);
163 strupper(p+5);
165 CVAL(p,21) = MAJOR_VERSION; /* major version */
166 CVAL(p,22) = MINOR_VERSION; /* minor version */
168 SIVAL(p,23,server_type);
169 /* browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT)*/
170 SSVAL(p,27,BROWSER_ELECTION_VERSION);
171 SSVAL(p,29,BROWSER_CONSTANT); /* browse signature */
173 strcpy(p+31,server_comment);
174 p += 31;
175 p = skip_string(p,1);
177 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
179 /* send the announcement */
180 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,outbuf,
181 PTR_DIFF(p,outbuf),
182 from_name, to_name,
183 from_type, to_type,
184 to_ip, from_ip);
188 /****************************************************************************
189 announce all samba's server entries as 'gone'.
190 ****************************************************************************/
191 void announce_my_servers_removed(void)
193 struct subnet_record *d;
194 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
196 struct work_record *work;
197 for (work = d->workgrouplist; work; work = work->next)
199 struct server_record *s;
200 for (s = work->serverlist; s; s = s->next)
202 if (!strequal(myname,s->serv.name)) continue;
203 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
210 /****************************************************************************
211 announce a server entry
212 ****************************************************************************/
213 void announce_server(struct subnet_record *d, struct work_record *work,
214 char *name, char *comment, time_t ttl, int server_type)
216 /* domain type cannot have anything in it that might confuse
217 a client into thinking that the domain is in fact a server.
218 (SV_TYPE_SERVER_UNIX, for example)
220 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
221 BOOL wins_iface = ip_equal(d->bcast_ip, wins_ip);
223 if (wins_iface && server_type != 0)
225 /* wins pseudo-ip interface */
226 if (!AM_MASTER(work))
228 /* non-master announce by unicast to the domain
229 master */
230 if (!lp_wins_support() && *lp_wins_server())
232 /* look up the domain master with the WINS server */
233 queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
234 NAME_QUERY_ANNOUNCE_HOST,
235 work->work_group,0x1b,0,ttl*1000,
236 server_type,name,comment,
237 False, False, ipzero, d->bcast_ip);
239 else
241 /* we are the WINS server, but not the domain master. */
242 /* XXXX we need to look up the domain master in our
243 WINS database list, and do_announce_host(). maybe
244 we could do a name query on the unsuspecting domain
245 master just to make sure it's awake. */
249 /* XXXX any other kinds of announcements we need to consider here?
250 e.g local master browsers... no. local master browsers do
251 local master announcements to their domain master. they even
252 use WINS lookup of the domain master if another wins server
253 is being used!
256 else
258 if (AM_MASTER(work))
260 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
261 inet_ntoa(d->bcast_ip),work->work_group));
263 do_announce_host(ANN_LocalMasterAnnouncement,
264 name , 0x00, d->myip,
265 work->work_group, 0x1e, d->bcast_ip,
266 ttl,
267 name, server_type, comment);
269 DEBUG(3,("sending domain announce to %s for %s\n",
270 inet_ntoa(d->bcast_ip),work->work_group));
272 /* XXXX should we do a domain-announce-kill? */
273 if (server_type != 0)
275 do_announce_host(ANN_DomainAnnouncement,
276 name , 0x00, d->myip,
277 MSBROWSE, 0x01, d->bcast_ip,
278 ttl,
279 work->work_group, server_type ? domain_type : 0,
280 name);
283 else
285 DEBUG(3,("sending host announce to %s for %s(1d)\n",
286 inet_ntoa(d->bcast_ip),work->work_group));
288 do_announce_host(ANN_HostAnnouncement,
289 name , 0x00, d->myip,
290 work->work_group, 0x1d, d->bcast_ip,
291 ttl,
292 name, server_type, comment);
297 /****************************************************************************
298 construct a host announcement unicast
299 **************************************************************************/
300 void announce_host(time_t t)
302 struct subnet_record *d;
303 pstring comment;
304 char *my_name;
306 StrnCpy(comment, lp_serverstring(), 43);
308 my_name = *myname ? myname : "NoName";
310 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
312 struct work_record *work;
314 for (work = d->workgrouplist; work; work = work->next)
316 uint32 stype = work->ServerType;
317 struct server_record *s;
318 BOOL announce = False;
320 /* must work on the code that does announcements at up to
321 30 seconds later if a master browser sends us a request
322 announce.
325 if (work->needannounce) {
326 /* drop back to a max 3 minute announce - this is to prevent a
327 single lost packet from stuffing things up for too long */
328 work->announce_interval = MIN(work->announce_interval,
329 CHECK_TIME_MIN_HOST_ANNCE*60);
330 work->lastannounce_time = t - (work->announce_interval+1);
333 /* announce every minute at first then progress to every 12 mins */
334 if (work->lastannounce_time &&
335 (t - work->lastannounce_time) < work->announce_interval)
336 continue;
338 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
339 work->announce_interval += 60;
341 work->lastannounce_time = t;
343 for (s = work->serverlist; s; s = s->next) {
344 if (strequal(myname, s->serv.name)) {
345 announce = True;
346 break;
350 if (announce) {
351 announce_server(d,work,my_name,comment,
352 work->announce_interval,stype);
355 if (work->needannounce)
357 work->needannounce = False;
358 break;
359 /* sorry: can't do too many announces. do some more later */
365 /* Announce timer. Moved into global static so it can be reset
366 when a machine becomes a master browser. */
367 static time_t announce_timer_last=0;
369 /****************************************************************************
370 Reset the announce_timer so that a master browser announce will be done
371 immediately.
372 ****************************************************************************/
374 void reset_announce_timer()
376 announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
379 /****************************************************************************
380 announce myself as a master to all other domain master browsers.
382 this actually gets done in search_and_sync_workgroups() via the
383 NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
384 name query initiated here. see response_name_query()
385 **************************************************************************/
386 void announce_master(time_t t)
388 struct subnet_record *d;
389 struct work_record *work;
390 BOOL am_master = False; /* are we a master of some sort? :-) */
392 if (!announce_timer_last) announce_timer_last = t;
393 if (t-announce_timer_last < CHECK_TIME_MST_ANNOUNCE * 60)
395 DEBUG(10,("announce_master: t (%d) - last(%d) < %d\n",
396 t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 ));
397 return;
400 if(wins_subnet == NULL)
402 DEBUG(10,("announce_master: no wins subnet, ignoring.\n"));
403 return;
406 announce_timer_last = t;
408 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
410 struct work_record *work;
411 for (work = d->workgrouplist; work; work = work->next)
413 if (AM_MASTER(work))
415 am_master = True;
416 DEBUG(4,( "announce_master: am_master = %d for \
417 workgroup %s\n", am_master, work->work_group));
422 if (!am_master) return; /* only proceed if we are a master browser */
424 /* Note that we don't do this if we are domain master browser
425 and that we *only* do this on the WINS subnet. */
427 /* Try and find our workgroup on the WINS subnet */
428 work = find_workgroupstruct(wins_subnet, myworkgroup, False);
430 if (work)
432 char *name;
433 int type;
435 #if 0 /* I don't think this option should be used for this purpose.
436 JRA.
438 if (*lp_domain_controller())
440 /* the domain controller option is used to manually specify
441 the domain master browser to sync with
444 /* XXXX i'm not sure we should be using the domain controller
445 option for this purpose.
448 name = lp_domain_controller();
449 type = 0x20;
451 else
452 #endif /* REMOVE SUSPECT CODE. */
454 /* assume that the domain master browser we want to sync
455 with is our own domain.
457 name = work->work_group;
458 type = 0x1b;
461 /* check the existence of a dmb for this workgroup, and if
462 one exists at the specified ip, sync with it and announce
463 ourselves as a master browser to it
466 if (!lp_wins_support() && *lp_wins_server() )
468 DEBUG(4, ("Local Announce: find %s<%02x> from WINS server %s\n",
469 name, type, lp_wins_server()));
471 queue_netbios_pkt_wins(ClientNMB,
472 NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
473 name, type, 0,0,0,
474 work->work_group,NULL,
475 False, False, ipzero, ipzero);
477 else if(lp_wins_support())
479 /* We are the WINS server - query ourselves for the dmb name. */
481 struct nmb_name netb_name;
482 struct subnet_record *d = 0;
483 struct name_record *nr = 0;
485 make_nmb_name(&netb_name, name, type, scope);
487 if ((nr = find_name_search(&d, &netb_name, FIND_WINS, ipzero)) == 0)
489 DEBUG(0, ("announce_master: unable to find domain master browser for workgroup %s \
490 in our own WINS database.\n", work->work_group));
491 return;
494 /* Check that this isn't one of our addresses (ie. we are not domain master
495 ourselves) */
496 if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero))
498 DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \
499 is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) ));
500 return;
503 /* Issue a NAME_STATUS_DOM_SRV_CHK immediately - short circuit the
504 NAME_QUERY_DOM_SRV_CHK which is done only if we are talking to a
505 remote WINS server. */
507 DEBUG(4, ("announce_master: doing name status for %s<%02x> to domain master ip %s \
508 for workgroup %s\n", name, type, inet_ntoa(nr->ip_flgs[0].ip), work->work_group ));
510 queue_netbios_packet(wins_subnet, ClientNMB,
511 NMB_QUERY,NAME_STATUS_DOM_SRV_CHK,
512 name, type, 0,0,0,
513 work->work_group,NULL,
514 False, False, nr->ip_flgs[0].ip, nr->ip_flgs[0].ip);
520 /****************************************************************************
521 do all the "remote" announcements. These are used to put ourselves
522 on a remote browse list. They are done blind, no checking is done to
523 see if there is actually a browse master at the other end.
524 **************************************************************************/
525 void announce_remote(time_t t)
527 char *s,*ptr;
528 static time_t last_time = 0;
529 pstring s2;
530 struct in_addr addr;
531 char *comment,*workgroup;
532 int stype = DFLT_SERVER_TYPE;
534 if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
535 return;
537 last_time = t;
539 s = lp_remote_announce();
540 if (!*s) return;
542 comment = lp_serverstring();
543 workgroup = myworkgroup;
545 for (ptr=s; next_token(&ptr,s2,NULL); ) {
546 /* the entries are of the form a.b.c.d/WORKGROUP with
547 WORKGROUP being optional */
548 char *wgroup;
550 wgroup = strchr(s2,'/');
551 if (wgroup) *wgroup++ = 0;
552 if (!wgroup || !*wgroup)
553 wgroup = workgroup;
555 addr = *interpret_addr2(s2);
557 do_announce_host(ANN_HostAnnouncement,myname,0x20,*iface_ip(addr),
558 wgroup,0x1e,addr,
559 REMOTE_ANNOUNCE_INTERVAL,
560 myname,stype,comment);