client.c: Added amanda fixes.
[Samba/ekacnet.git] / source / nameannounce.c
bloba8fdde19bbff870fe3b2658550c392f708634e12
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 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1997
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 Revision History:
26 14 jan 96: lkcl@pires.co.uk
27 added multiple workgroup domain master support
31 #include "includes.h"
33 #define TEST_CODE
35 extern int DEBUGLEVEL;
36 extern BOOL CanRecurse;
38 extern struct in_addr ipzero;
40 extern pstring myname;
41 extern fstring myworkgroup;
43 extern int ClientDGRAM;
44 extern int ClientNMB;
46 /* this is our domain/workgroup/server database */
47 extern struct subnet_record *subnetlist;
49 extern int updatecount;
50 extern int workgroup_count;
52 extern struct in_addr wins_ip;
54 extern pstring scope;
56 /****************************************************************************
57 send a announce request to the local net
58 **************************************************************************/
59 void announce_request(struct work_record *work, struct in_addr ip)
61 pstring outbuf;
62 char *p;
64 if (!work) return;
66 work->needannounce = True;
68 DEBUG(2,("sending announce request to %s for workgroup %s\n",
69 inet_ntoa(ip),work->work_group));
71 bzero(outbuf,sizeof(outbuf));
72 p = outbuf;
73 CVAL(p,0) = ANN_AnnouncementRequest;
74 p++;
76 CVAL(p,0) = work->token; /* (local) unique workgroup token id */
77 p++;
78 StrnCpy(p,myname,16);
79 strupper(p);
80 p = skip_string(p,1);
82 /* XXXX note: if we sent the announcement request to 0x1d instead
83 of 0x1e, then we could get the master browser to announce to
84 us instead of the members of the workgroup. wha-hey! */
86 send_mailslot_reply(False, BROWSE_MAILSLOT,ClientDGRAM,
87 outbuf,PTR_DIFF(p,outbuf),
88 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
92 /****************************************************************************
93 request an announcement
94 **************************************************************************/
95 void do_announce_request(char *info, char *to_name, int announce_type,
96 int from,
97 int to, struct in_addr dest_ip)
99 pstring outbuf;
100 char *p;
102 bzero(outbuf,sizeof(outbuf));
103 p = outbuf;
104 CVAL(p,0) = announce_type;
105 p++;
107 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
108 announce_type, info, inet_ntoa(dest_ip),to_name,to));
110 StrnCpy(p,info,16);
111 strupper(p);
112 p = skip_string(p,1);
114 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
115 outbuf,PTR_DIFF(p,outbuf),
116 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
120 /****************************************************************************
121 find a server responsible for a workgroup, and sync browse lists
122 control ends up back here via response_name_query.
123 **************************************************************************/
124 void sync_server(enum state_type state, char *serv_name, char *work_name,
125 int name_type,
126 struct subnet_record *d,
127 struct in_addr ip)
129 /* with a domain master we can get the whole list (not local only list) */
130 BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
132 add_browser_entry(serv_name, name_type, work_name, 0, d, ip, local_only);
134 if (state == NAME_STATUS_DOM_SRV_CHK)
136 /* announce ourselves as a master browser to serv_name */
137 do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
138 0x20, 0, ip);
143 /****************************************************************************
144 send a host announcement packet
145 **************************************************************************/
146 void do_announce_host(int command,
147 char *from_name, int from_type, struct in_addr from_ip,
148 char *to_name , int to_type , struct in_addr to_ip,
149 time_t announce_interval,
150 char *server_name, int server_type, char *server_comment)
152 pstring outbuf;
153 char *p;
155 bzero(outbuf,sizeof(outbuf));
156 p = outbuf+1;
158 /* command type */
159 CVAL(outbuf,0) = command;
161 /* announcement parameters */
162 CVAL(p,0) = updatecount;
163 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
165 StrnCpy(p+5,server_name,16);
166 strupper(p+5);
168 CVAL(p,21) = MAJOR_VERSION; /* major version */
169 CVAL(p,22) = MINOR_VERSION; /* minor version */
171 SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
172 /* browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT)*/
173 SSVAL(p,27,BROWSER_ELECTION_VERSION);
174 SSVAL(p,29,BROWSER_CONSTANT); /* browse signature */
176 strcpy(p+31,server_comment);
177 p += 31;
178 p = skip_string(p,1);
180 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
182 /* send the announcement */
183 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,outbuf,
184 PTR_DIFF(p,outbuf),
185 from_name, to_name,
186 from_type, to_type,
187 to_ip, from_ip);
191 /****************************************************************************
192 announce all samba's server entries as 'gone'.
193 ****************************************************************************/
194 void announce_my_servers_removed(void)
196 struct subnet_record *d;
197 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
199 struct work_record *work;
200 for (work = d->workgrouplist; work; work = work->next)
202 struct server_record *s;
203 for (s = work->serverlist; s; s = s->next)
205 if (!strequal(myname,s->serv.name)) continue;
206 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
213 /****************************************************************************
214 announce a server entry
215 ****************************************************************************/
216 void announce_server(struct subnet_record *d, struct work_record *work,
217 char *name, char *comment, time_t ttl, int server_type)
219 /* domain type cannot have anything in it that might confuse
220 a client into thinking that the domain is in fact a server.
221 (SV_TYPE_SERVER_UNIX, for example)
223 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
224 BOOL wins_iface = ip_equal(d->bcast_ip, wins_ip);
226 if(wins_iface)
228 DEBUG(0,("announce_server: error - announcement requested on WINS \
229 interface for workgroup %s, name %s\n", work->work_group, name));
230 return;
233 if (AM_MASTER(work))
235 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
236 inet_ntoa(d->bcast_ip),work->work_group));
238 do_announce_host(ANN_LocalMasterAnnouncement,
239 name , 0x00, d->myip,
240 work->work_group, 0x1e, d->bcast_ip,
241 ttl,
242 name, server_type, comment);
244 DEBUG(3,("sending domain announce to %s for %s\n",
245 inet_ntoa(d->bcast_ip),work->work_group));
247 /* XXXX should we do a domain-announce-kill? */
248 if (server_type != 0)
250 do_announce_host(ANN_DomainAnnouncement,
251 name , 0x00, d->myip,
252 MSBROWSE, 0x01, d->bcast_ip,
253 ttl,
254 work->work_group, server_type ? domain_type : 0,
255 name);
258 else
260 DEBUG(3,("sending host announce to %s for %s(1d)\n",
261 inet_ntoa(d->bcast_ip),work->work_group));
263 do_announce_host(ANN_HostAnnouncement,
264 name , 0x00, d->myip,
265 work->work_group, 0x1d, d->bcast_ip,
266 ttl,
267 name, server_type, comment);
271 /****************************************************************************
272 construct a host announcement unicast
273 **************************************************************************/
274 void announce_host(time_t t)
276 struct subnet_record *d;
277 pstring comment;
278 char *my_name;
280 StrnCpy(comment, lp_serverstring(), 43);
282 my_name = *myname ? myname : "NoName";
284 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
286 struct work_record *work;
288 for (work = d->workgrouplist; work; work = work->next)
290 uint32 stype = work->ServerType;
291 struct server_record *s;
292 BOOL announce = False;
294 /* must work on the code that does announcements at up to
295 30 seconds later if a master browser sends us a request
296 announce.
299 if (work->needannounce) {
300 /* drop back to a max 3 minute announce - this is to prevent a
301 single lost packet from stuffing things up for too long */
302 work->announce_interval = MIN(work->announce_interval,
303 CHECK_TIME_MIN_HOST_ANNCE*60);
304 work->lastannounce_time = t - (work->announce_interval+1);
307 /* announce every minute at first then progress to every 12 mins */
308 if (work->lastannounce_time &&
309 (t - work->lastannounce_time) < work->announce_interval)
310 continue;
312 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
313 work->announce_interval += 60;
315 work->lastannounce_time = t;
317 for (s = work->serverlist; s; s = s->next) {
318 if (strequal(myname, s->serv.name)) {
319 announce = True;
320 break;
324 if (announce) {
325 announce_server(d,work,my_name,comment,
326 work->announce_interval,stype);
329 if (work->needannounce)
331 work->needannounce = False;
332 break;
333 /* sorry: can't do too many announces. do some more later */
339 /* Announce timer. Moved into global static so it can be reset
340 when a machine becomes a master browser. */
341 static time_t announce_timer_last=0;
343 /****************************************************************************
344 Reset the announce_timer so that a master browser announce will be done
345 immediately.
346 ****************************************************************************/
348 void reset_announce_timer()
350 announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
353 /****************************************************************************
354 announce myself as a master to all other domain master browsers.
356 this actually gets done in search_and_sync_workgroups() via the
357 NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
358 name query initiated here. see response_name_query()
359 **************************************************************************/
360 void announce_master(time_t t)
362 struct subnet_record *d;
363 struct work_record *work;
364 BOOL am_master = False; /* are we a master of some sort? :-) */
366 if (!announce_timer_last) announce_timer_last = t;
367 if (t-announce_timer_last < CHECK_TIME_MST_ANNOUNCE * 60)
369 DEBUG(10,("announce_master: t (%d) - last(%d) < %d\n",
370 t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 ));
371 return;
374 if(wins_subnet == NULL)
376 DEBUG(10,("announce_master: no wins subnet, ignoring.\n"));
377 return;
380 announce_timer_last = t;
382 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
384 struct work_record *work;
385 for (work = d->workgrouplist; work; work = work->next)
387 if (AM_MASTER(work))
389 am_master = True;
390 DEBUG(4,( "announce_master: am_master = %d for \
391 workgroup %s\n", am_master, work->work_group));
396 if (!am_master) return; /* only proceed if we are a master browser */
398 /* Note that we don't do this if we are domain master browser
399 and that we *only* do this on the WINS subnet. */
401 /* Try and find our workgroup on the WINS subnet */
402 work = find_workgroupstruct(wins_subnet, myworkgroup, False);
404 if (work)
406 char *name;
407 int type;
410 /* assume that the domain master browser we want to sync
411 with is our own domain.
413 name = work->work_group;
414 type = 0x1b;
417 /* check the existence of a dmb for this workgroup, and if
418 one exists at the specified ip, sync with it and announce
419 ourselves as a master browser to it
422 if (!lp_wins_support() && *lp_wins_server() )
424 DEBUG(4, ("Local Announce: find %s<%02x> from WINS server %s\n",
425 name, type, lp_wins_server()));
427 queue_netbios_pkt_wins(ClientNMB,
428 NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
429 name, type, 0,0,0,
430 work->work_group,NULL,
431 False, True, ipzero, ipzero);
433 else if(lp_wins_support())
435 /* We are the WINS server - query ourselves for the dmb name. */
437 struct nmb_name netb_name;
438 struct subnet_record *d = 0;
439 struct name_record *nr = 0;
441 make_nmb_name(&netb_name, name, type, scope);
443 if ((nr = find_name_search(&d, &netb_name, FIND_WINS, ipzero)) == 0)
445 DEBUG(0, ("announce_master: unable to find domain master browser for workgroup %s \
446 in our own WINS database.\n", work->work_group));
447 return;
450 /* Check that this isn't one of our addresses (ie. we are not domain master
451 ourselves) */
452 if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero))
454 DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \
455 is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) ));
456 return;
459 /* Issue a NAME_STATUS_DOM_SRV_CHK immediately - short circuit the
460 NAME_QUERY_DOM_SRV_CHK which is done only if we are talking to a
461 remote WINS server. */
463 DEBUG(4, ("announce_master: doing name status for %s<%02x> to domain master ip %s \
464 for workgroup %s\n", name, type, inet_ntoa(nr->ip_flgs[0].ip), work->work_group ));
466 queue_netbios_packet(wins_subnet, ClientNMB,
467 NMB_QUERY,NAME_STATUS_DOM_SRV_CHK,
468 name, type, 0,0,0,
469 work->work_group,NULL,
470 False, False, nr->ip_flgs[0].ip, nr->ip_flgs[0].ip);
476 /****************************************************************************
477 do all the "remote" announcements. These are used to put ourselves
478 on a remote browse list. They are done blind, no checking is done to
479 see if there is actually a browse master at the other end.
480 **************************************************************************/
481 void announce_remote(time_t t)
483 char *s,*ptr;
484 static time_t last_time = 0;
485 pstring s2;
486 struct in_addr addr;
487 char *comment,*workgroup;
488 int stype = DFLT_SERVER_TYPE;
490 if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
491 return;
493 last_time = t;
495 s = lp_remote_announce();
496 if (!*s) return;
498 comment = lp_serverstring();
499 workgroup = myworkgroup;
501 for (ptr=s; next_token(&ptr,s2,NULL); ) {
502 /* the entries are of the form a.b.c.d/WORKGROUP with
503 WORKGROUP being optional */
504 char *wgroup;
506 wgroup = strchr(s2,'/');
507 if (wgroup) *wgroup++ = 0;
508 if (!wgroup || !*wgroup)
509 wgroup = workgroup;
511 addr = *interpret_addr2(s2);
513 do_announce_host(ANN_HostAnnouncement,myname,0x20,*iface_ip(addr),
514 wgroup,0x1e,addr,
515 REMOTE_ANNOUNCE_INTERVAL,
516 myname,stype,comment);