This commit was manufactured by cvs2svn to create tag
[Samba/gbeck.git] / source / nameannounce.c
blob1dadc0132c193502d2603fe063c60781ae78480f
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
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;
39 extern int ClientDGRAM;
40 extern int ClientNMB;
42 /* this is our domain/workgroup/server database */
43 extern struct subnet_record *subnetlist;
45 extern int updatecount;
46 extern int workgroup_count;
48 extern struct in_addr ipgrp;
52 /****************************************************************************
53 send a announce request to the local net
54 **************************************************************************/
55 void announce_request(struct work_record *work, struct in_addr ip)
57 pstring outbuf;
58 char *p;
60 if (!work) return;
62 work->needannounce = True;
64 DEBUG(2,("sending announce request to %s for workgroup %s\n",
65 inet_ntoa(ip),work->work_group));
67 bzero(outbuf,sizeof(outbuf));
68 p = outbuf;
69 CVAL(p,0) = ANN_AnnouncementRequest;
70 p++;
72 CVAL(p,0) = work->token; /* (local) unique workgroup token id */
73 p++;
74 StrnCpy(p,myname,16);
75 strupper(p);
76 p = skip_string(p,1);
78 /* XXXX note: if we sent the announcement request to 0x1d instead
79 of 0x1e, then we could get the master browser to announce to
80 us instead of the members of the workgroup. wha-hey! */
82 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
83 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
87 /****************************************************************************
88 request an announcement
89 **************************************************************************/
90 void do_announce_request(char *info, char *to_name, int announce_type,
91 int from,
92 int to, struct in_addr dest_ip)
94 pstring outbuf;
95 char *p;
97 bzero(outbuf,sizeof(outbuf));
98 p = outbuf;
99 CVAL(p,0) = announce_type;
100 p++;
102 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
103 announce_type, info, inet_ntoa(dest_ip),to_name,to));
105 StrnCpy(p,info,16);
106 strupper(p);
107 p = skip_string(p,1);
109 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
110 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
114 /****************************************************************************
115 find a server responsible for a workgroup, and sync browse lists
116 control ends up back here via response_name_query.
117 **************************************************************************/
118 void sync_server(enum state_type state, char *serv_name, char *work_name,
119 int name_type,
120 struct in_addr ip)
122 /* with a domain master we can get the whole list (not local only list) */
123 BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
125 add_browser_entry(serv_name, name_type, work_name, 0, ip, local_only);
127 if (state == NAME_STATUS_DOM_SRV_CHK)
129 /* announce ourselves as a master browser to serv_name */
130 do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
131 0x20, 0, ip);
136 /****************************************************************************
137 send a host announcement packet
138 **************************************************************************/
139 void do_announce_host(int command,
140 char *from_name, int from_type, struct in_addr from_ip,
141 char *to_name , int to_type , struct in_addr to_ip,
142 time_t announce_interval,
143 char *server_name, int server_type, char *server_comment)
145 pstring outbuf;
146 char *p;
148 bzero(outbuf,sizeof(outbuf));
149 p = outbuf+1;
151 /* command type */
152 CVAL(outbuf,0) = command;
154 /* announcement parameters */
155 CVAL(p,0) = updatecount;
156 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
158 StrnCpy(p+5,server_name,16);
159 strupper(p+5);
161 CVAL(p,21) = 0x02; /* major version */
162 CVAL(p,22) = 0x02; /* minor version */
164 SIVAL(p,23,server_type);
165 SSVAL(p,27,0x010f); /* browse version: got from NT/AS 4.00 */
166 SSVAL(p,29,0xaa55); /* browse signature */
168 strcpy(p+31,server_comment);
169 p += 31;
170 p = skip_string(p,1);
172 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
174 /* send the announcement */
175 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
176 PTR_DIFF(p,outbuf),
177 from_name, to_name,
178 from_type, to_type,
179 to_ip, from_ip);
183 /****************************************************************************
184 remove all samba's server entries
185 ****************************************************************************/
186 void remove_my_servers(void)
188 struct subnet_record *d;
189 for (d = subnetlist; d; d = d->next)
191 struct work_record *work;
192 for (work = d->workgrouplist; work; work = work->next)
194 struct server_record *s;
195 for (s = work->serverlist; s; s = s->next)
197 if (!strequal(myname,s->serv.name)) continue;
198 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
205 /****************************************************************************
206 announce a server entry
207 ****************************************************************************/
208 void announce_server(struct subnet_record *d, struct work_record *work,
209 char *name, char *comment, time_t ttl, int server_type)
211 /* domain type cannot have anything in it that might confuse
212 a client into thinking that the domain is in fact a server.
213 (SV_TYPE_SERVER_UNIX, for example)
215 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
216 BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp);
218 if (wins_iface && server_type != 0)
220 /* wins pseudo-ip interface */
221 if (!AM_MASTER(work))
223 /* non-master announce by unicast to the domain
224 master */
225 if (!lp_wins_support() && *lp_wins_server())
227 /* look up the domain master with the WINS server */
228 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
229 NAME_QUERY_ANNOUNCE_HOST,
230 work->work_group,0x1b,0,ttl*1000,
231 server_type,name,comment,
232 False, False, ipzero, d->bcast_ip);
234 else
236 /* we are the WINS server, but not the domain master. */
237 /* XXXX we need to look up the domain master in our
238 WINS database list, and do_announce_host(). maybe
239 we could do a name query on the unsuspecting domain
240 master just to make sure it's awake. */
244 /* XXXX any other kinds of announcements we need to consider here?
245 e.g local master browsers... no. local master browsers do
246 local master announcements to their domain master. they even
247 use WINS lookup of the domain master if another wins server
248 is being used!
251 else
253 if (AM_MASTER(work))
255 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
256 inet_ntoa(d->bcast_ip),work->work_group));
258 do_announce_host(ANN_LocalMasterAnnouncement,
259 name , 0x00, d->myip,
260 work->work_group, 0x1e, d->bcast_ip,
261 ttl*1000,
262 name, server_type, comment);
264 DEBUG(3,("sending domain announce to %s for %s\n",
265 inet_ntoa(d->bcast_ip),work->work_group));
267 /* XXXX should we do a domain-announce-kill? */
268 if (server_type != 0)
270 do_announce_host(ANN_DomainAnnouncement,
271 name , 0x00, d->myip,
272 MSBROWSE, 0x01, d->bcast_ip,
273 ttl*1000,
274 work->work_group, server_type ? domain_type : 0,
275 name);
278 else
280 DEBUG(3,("sending host announce to %s for %s(1d)\n",
281 inet_ntoa(d->bcast_ip),work->work_group));
283 do_announce_host(ANN_HostAnnouncement,
284 name , 0x00, d->myip,
285 work->work_group, 0x1d, d->bcast_ip,
286 ttl*1000,
287 name, server_type, comment);
292 /****************************************************************************
293 construct a host announcement unicast
294 **************************************************************************/
295 void announce_host(time_t t)
297 struct subnet_record *d;
298 pstring comment;
299 char *my_name;
301 StrnCpy(comment, lp_serverstring(), 43);
303 my_name = *myname ? myname : "NoName";
305 for (d = subnetlist; d; d = d->next)
307 struct work_record *work;
309 if (ip_equal(d->bcast_ip, ipgrp)) continue;
311 for (work = d->workgrouplist; work; work = work->next)
313 uint32 stype = work->ServerType;
314 struct server_record *s;
315 BOOL announce = False;
317 /* must work on the code that does announcements at up to
318 30 seconds later if a master browser sends us a request
319 announce.
322 if (work->needannounce) {
323 /* drop back to a max 3 minute announce - this is to prevent a
324 single lost packet from stuffing things up for too long */
325 work->announce_interval = MIN(work->announce_interval,
326 CHECK_TIME_MIN_HOST_ANNCE*60);
327 work->lastannounce_time = t - (work->announce_interval+1);
330 /* announce every minute at first then progress to every 12 mins */
331 if (work->lastannounce_time &&
332 (t - work->lastannounce_time) < work->announce_interval)
333 continue;
335 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
336 work->announce_interval += 60;
338 work->lastannounce_time = t;
340 for (s = work->serverlist; s; s = s->next) {
341 if (strequal(myname, s->serv.name)) {
342 announce = True;
343 break;
347 if (announce) {
348 announce_server(d,work,my_name,comment,
349 work->announce_interval,stype);
352 if (work->needannounce)
354 work->needannounce = False;
355 break;
356 /* sorry: can't do too many announces. do some more later */
363 /****************************************************************************
364 announce myself as a master to all other primary domain conrollers.
366 this actually gets done in search_and_sync_workgroups() via the
367 NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
368 name query initiated here. see response_name_query()
369 **************************************************************************/
370 void announce_master(time_t t)
372 struct subnet_record *d;
373 static time_t last=0;
374 BOOL am_master = False; /* are we a master of some sort? :-) */
376 if (!last) last = t;
377 if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
378 return;
380 last = t;
382 for (d = subnetlist; d; d = d->next)
384 struct work_record *work;
385 for (work = d->workgrouplist; work; work = work->next)
387 if (AM_MASTER(work))
389 am_master = True;
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 DOMs (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())
418 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
419 NAME_QUERY_DOM_SRV_CHK,
420 work->work_group,0x1b,0,0,0,NULL,NULL,
421 False, False, ipzero, ipzero);
423 else
425 struct subnet_record *d2;
426 for (d2 = subnetlist; d2; d2 = d2->next)
428 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
429 NAME_QUERY_DOM_SRV_CHK,
430 work->work_group,0x1b,0,0,0,NULL,NULL,
431 True, False, d2->bcast_ip, d2->bcast_ip);
438 /* now do primary domain controller - the one that's not
439 necessarily in our browse lists, although it ought to be
440 this pdc is the one that we get TOLD about through smb.conf.
441 basically, if it's on a subnet that we know about, it may end
442 up in our browse lists (which is why it's explicitly excluded
443 in the code above) */
445 if (*lp_domain_controller())
447 struct in_addr ip;
448 BOOL bcast = False;
450 ip = *interpret_addr2(lp_domain_controller());
452 if (zero_ip(ip)) {
453 ip = d->bcast_ip;
454 bcast = True;
457 DEBUG(2, ("Searching for DOM %s at %s\n",
458 lp_domain_controller(), inet_ntoa(ip)));
460 /* check the existence of a pdc for this workgroup, and if
461 one exists at the specified ip, sync with it and announce
462 ourselves as a master browser to it */
463 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
464 work->work_group,0x1b,0,0,0,NULL,NULL,
465 bcast, False, ip, ip);
473 /****************************************************************************
474 do all the "remote" announcements. These are used to put ourselves
475 on a remote browse list. They are done blind, no checking is done to
476 see if there is actually a browse master at the other end.
477 **************************************************************************/
478 void announce_remote(time_t t)
480 char *s,*ptr;
481 static time_t last_time = 0;
482 pstring s2;
483 struct in_addr addr;
484 char *comment,*workgroup;
485 int stype = DFLT_SERVER_TYPE;
487 if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
488 return;
490 last_time = t;
492 s = lp_remote_announce();
493 if (!*s) return;
495 comment = lp_serverstring();
496 workgroup = lp_workgroup();
498 for (ptr=s; next_token(&ptr,s2,NULL); ) {
499 /* the entries are of the form a.b.c.d/WORKGROUP with
500 WORKGROUP being optional */
501 char *wgroup;
503 wgroup = strchr(s2,'/');
504 if (wgroup) *wgroup++ = 0;
505 if (!wgroup || !*wgroup)
506 wgroup = workgroup;
508 addr = *interpret_addr2(s2);
510 do_announce_host(ANN_HostAnnouncement,myname,0x20,*iface_ip(addr),
511 wgroup,0x1e,addr,
512 REMOTE_ANNOUNCE_INTERVAL,
513 myname,stype,comment);