updated comments in announce_server() to indicate that future work needs
[Samba.git] / source / nameannounce.c
blobe619ef1c4b624a382e7b865a82cc33fe76e82dd3
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 /* 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)
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(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,
92 int from,
93 int to, struct in_addr dest_ip)
95 pstring outbuf;
96 char *p;
98 bzero(outbuf,sizeof(outbuf));
99 p = outbuf;
100 CVAL(p,0) = announce_type;
101 p++;
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));
106 StrnCpy(p,info,16);
107 strupper(p);
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,
120 int name_type,
121 struct in_addr ip)
123 /* with a domain master we can get the whole list (not local only list) */
124 BOOL local_only = state != NAME_STATUS_DOM_SRV_CHK;
126 add_browser_entry(serv_name, name_type, work_name, 0, ip, local_only);
128 if (state == NAME_STATUS_DOM_SRV_CHK)
130 /* announce ourselves as a master browser to serv_name */
131 do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
132 0x20, 0, ip);
137 /****************************************************************************
138 construct a host announcement unicast
140 this function should not be used heavily, and only when we are _not_
141 a master browser and _not_ a primary domain controller.
143 **************************************************************************/
144 void announce_backup(void)
146 static time_t lastrun = 0;
147 time_t t = time(NULL);
148 pstring outbuf;
149 char *p;
150 struct subnet_record *d1;
151 int tok;
152 static uint32 id_count = 0;
154 if (!lastrun) lastrun = t;
155 #if 1
156 if (t < lastrun + 1 * 60)
157 #else
158 if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
159 #endif
160 return;
161 lastrun = t;
163 DEBUG(4,("checking backups...\n"));
165 for (tok = 0; tok <= workgroup_count; tok++)
167 for (d1 = subnetlist; d1; d1 = d1->next)
169 struct work_record *work;
170 struct subnet_record *d;
172 /* search for unique workgroup: only the name matters */
173 for (work = d1->workgrouplist;
174 work && (tok != work->token);
175 work = work->next);
177 if (!work) continue;
179 if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
181 /* found one: announce it across all domains */
182 for (d = subnetlist; d; d = d->next)
185 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
186 inet_ntoa(d->bcast_ip),work->work_group,
187 work->token));
189 bzero(outbuf,sizeof(outbuf));
190 p = outbuf;
192 CVAL(p,0) = ANN_GetBackupListReq;
193 CVAL(p,1) = work->token; /* workgroup unique key index */
194 SIVAL(p,2,++id_count); /* unique count. not that we use it! */
196 p += 6;
198 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
200 if (!AM_DOMCTL(work))
202 /* only ask for a list of backup domain controllers
203 if we are not a domain controller ourselves */
205 send_mailslot_reply(BROWSE_MAILSLOT,
206 ClientDGRAM,outbuf,
207 PTR_DIFF(p,outbuf),
208 myname, work->work_group,
209 0x0,0x1b,d->bcast_ip,
210 *iface_ip(d->bcast_ip));
213 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
215 if (!AM_MASTER(work))
217 /* only ask for a list of master browsers if we
218 are not a master browser ourselves */
220 send_mailslot_reply(BROWSE_MAILSLOT,
221 ClientDGRAM,outbuf,
222 PTR_DIFF(p,outbuf),
223 myname, work->work_group,
224 0x0,0x1d,d->bcast_ip,
225 *iface_ip(d->bcast_ip));
233 /****************************************************************************
234 send a host announcement packet
235 **************************************************************************/
236 void do_announce_host(int command,
237 char *from_name, int from_type, struct in_addr from_ip,
238 char *to_name , int to_type , struct in_addr to_ip,
239 time_t announce_interval,
240 char *server_name, int server_type, char *server_comment)
242 pstring outbuf;
243 char *p;
245 bzero(outbuf,sizeof(outbuf));
246 p = outbuf+1;
248 /* command type */
249 CVAL(outbuf,0) = command;
251 /* announcement parameters */
252 CVAL(p,0) = updatecount;
253 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
255 StrnCpy(p+5,server_name,16);
256 strupper(p+5);
258 CVAL(p,21) = 0x02; /* major version */
259 CVAL(p,22) = 0x02; /* minor version */
261 SIVAL(p,23,server_type);
262 SSVAL(p,27,0x010f); /* browse version: got from NT/AS 4.00 */
263 SSVAL(p,29,0xaa55); /* browse signature */
265 strcpy(p+31,server_comment);
266 p += 31;
267 p = skip_string(p,1);
269 debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
271 /* send the announcement */
272 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
273 PTR_DIFF(p,outbuf),
274 from_name, to_name,
275 from_type, to_type,
276 to_ip, from_ip);
280 /****************************************************************************
281 remove all samba's server entries
282 ****************************************************************************/
283 void remove_my_servers(void)
285 struct subnet_record *d;
286 for (d = subnetlist; d; d = d->next)
288 struct work_record *work;
289 for (work = d->workgrouplist; work; work = work->next)
291 struct server_record *s;
292 for (s = work->serverlist; s; s = s->next)
294 if (!strequal(myname,s->serv.name)) continue;
295 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
302 /****************************************************************************
303 announce a server entry
304 ****************************************************************************/
305 void announce_server(struct subnet_record *d, struct work_record *work,
306 char *name, char *comment, time_t ttl, int server_type)
308 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX;
309 BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp);
311 if (wins_iface && server_type != 0)
313 /* wins pseudo-ip interface */
314 if (!AM_MASTER(work))
316 /* non-master announce by unicast to the domain master */
317 if (!lp_wins_support() && *lp_wins_server())
319 /* look up the domain master with the WINS server */
320 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
321 NAME_QUERY_ANNOUNCE_HOST,
322 work->work_group,0x1b,0,ttl*1000,
323 server_type,name,comment,
324 False, False, ipzero, d->bcast_ip);
326 else
328 /* we are the WINS server, but not the domain master. */
329 /* XXXX we need to look up the domain master in our
330 WINS database list, and do_announce_host(). maybe
331 we could do a name query on the unsuspecting domain
332 master just to make sure it's awake. */
336 if (AM_DOMCTL(work))
338 /* XXXX announce to backup domain masters? */
341 /* XXXX any other kinds of announcements we need to consider here?
342 e.g local master browsers... no. local master browsers do
343 local master announcements to their domain master. they even
344 use WINS lookup of the domain master if another wins server
345 is being used!
348 else
350 if (AM_MASTER(work))
352 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
353 inet_ntoa(d->bcast_ip),work->work_group));
355 do_announce_host(ANN_LocalMasterAnnouncement,
356 name , 0x00, d->myip,
357 work->work_group, 0x1e, d->bcast_ip,
358 ttl*1000,
359 name, server_type, comment);
361 DEBUG(3,("sending domain announce to %s for %s\n",
362 inet_ntoa(d->bcast_ip),work->work_group));
364 /* XXXX should we do a domain-announce-kill? */
365 if (server_type != 0)
367 if (AM_DOMCTL(work))
369 domain_type |= SV_TYPE_DOMAIN_CTRL;
371 do_announce_host(ANN_DomainAnnouncement,
372 name , 0x00, d->myip,
373 MSBROWSE, 0x01, d->bcast_ip,
374 ttl*1000,
375 work->work_group, server_type ? domain_type : 0,
376 name);
379 else
381 DEBUG(3,("sending host announce to %s for %s(1d)\n",
382 inet_ntoa(d->bcast_ip),work->work_group));
384 do_announce_host(ANN_HostAnnouncement,
385 name , 0x00, d->myip,
386 work->work_group, 0x1d, d->bcast_ip,
387 ttl*1000,
388 name, server_type, comment);
393 /****************************************************************************
394 construct a host announcement unicast
395 **************************************************************************/
396 void announce_host(void)
398 time_t t = time(NULL);
399 struct subnet_record *d;
400 pstring comment;
401 char *my_name;
403 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
405 my_name = *myname ? myname : "NoName";
407 for (d = subnetlist; d; d = d->next)
409 struct work_record *work;
411 if (ip_equal(d->bcast_ip, ipgrp)) continue;
413 for (work = d->workgrouplist; work; work = work->next)
415 uint32 stype = work->ServerType;
416 struct server_record *s;
417 BOOL announce = False;
419 /* must work on the code that does announcements at up to
420 30 seconds later if a master browser sends us a request
421 announce.
424 if (work->needannounce) {
425 /* drop back to a max 3 minute announce - this is to prevent a
426 single lost packet from stuffing things up for too long */
427 work->announce_interval = MIN(work->announce_interval,
428 CHECK_TIME_MIN_HOST_ANNCE*60);
429 work->lastannounce_time = t - (work->announce_interval+1);
432 /* announce every minute at first then progress to every 12 mins */
433 if (work->lastannounce_time &&
434 (t - work->lastannounce_time) < work->announce_interval)
435 continue;
437 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
438 work->announce_interval += 60;
440 work->lastannounce_time = t;
443 if (!d->my_interface) {
444 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
445 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
446 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
450 for (s = work->serverlist; s; s = s->next) {
451 if (strequal(myname, s->serv.name)) {
452 announce = True;
453 break;
457 if (announce)
459 announce_server(d,work,my_name,comment,work->announce_interval,stype);
462 if (work->needannounce)
464 work->needannounce = False;
465 break;
466 /* sorry: can't do too many announces. do some more later */
473 /****************************************************************************
474 announce myself as a master to all other primary domain conrollers.
476 BIG NOTE: this code will remain untested until some kind soul that has access
477 to a couple of windows NT advanced servers runs this version of nmbd for at
478 least 15 minutes.
480 this actually gets done in search_and_sync_workgroups() via the
481 NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
482 name query initiated here. see response_name_query()
483 **************************************************************************/
484 void announce_master(void)
486 struct subnet_record *d;
487 static time_t last=0;
488 time_t t = time(NULL);
489 BOOL am_master = False; /* are we a master of some sort? :-) */
491 if (!last) last = t;
492 if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
493 return;
495 last = t;
497 for (d = subnetlist; d; d = d->next)
499 struct work_record *work;
500 for (work = d->workgrouplist; work; work = work->next)
502 if (AM_MASTER(work))
504 am_master = True;
509 if (!am_master) return; /* only proceed if we are a master browser */
511 for (d = subnetlist; d; d = d->next)
513 struct work_record *work;
514 for (work = d->workgrouplist; work; work = work->next)
516 struct server_record *s;
517 for (s = work->serverlist; s; s = s->next)
519 if (strequal(s->serv.name, myname)) continue;
521 /* all DOMs (which should also be master browsers) */
522 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
524 /* check the existence of a pdc for this workgroup, and if
525 one exists at the specified ip, sync with it and announce
526 ourselves as a master browser to it */
528 if (!*lp_domain_controller() ||
529 !strequal(lp_domain_controller(), s->serv.name))
531 if (!lp_wins_support() && *lp_wins_server())
533 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
534 NAME_QUERY_DOM_SRV_CHK,
535 work->work_group,0x1b,0,0,0,NULL,NULL,
536 False, False, ipzero, ipzero);
538 else
540 struct subnet_record *d2;
541 for (d2 = subnetlist; d2; d2 = d2->next)
543 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
544 NAME_QUERY_DOM_SRV_CHK,
545 work->work_group,0x1b,0,0,0,NULL,NULL,
546 True, False, d2->bcast_ip, d2->bcast_ip);
553 /* now do primary domain controller - the one that's not
554 necessarily in our browse lists, although it ought to be
555 this pdc is the one that we get TOLD about through smb.conf.
556 basically, if it's on a subnet that we know about, it may end
557 up in our browse lists (which is why it's explicitly excluded
558 in the code above) */
560 if (*lp_domain_controller())
562 struct in_addr ip;
563 BOOL bcast = False;
565 ip = *interpret_addr2(lp_domain_controller());
567 if (zero_ip(ip)) {
568 ip = d->bcast_ip;
569 bcast = True;
572 DEBUG(2, ("Searching for DOM %s at %s\n",
573 lp_domain_controller(), inet_ntoa(ip)));
575 /* check the existence of a pdc for this workgroup, and if
576 one exists at the specified ip, sync with it and announce
577 ourselves as a master browser to it */
578 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
579 work->work_group,0x1b,0,0,0,NULL,NULL,
580 bcast, False, ip, ip);