updating documentation to reflect code a little bit.
[Samba.git] / source / nameannounce.c
blobff6ee18cd12814813af8e53a4e31c11f26dc9142
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 what's going on??? and we're not going to deal with
330 this case, right now
335 if (AM_DOMCTL(work))
337 /* XXXX announce to backup domain masters? */
340 /* XXXX any other kinds of announcements we need to consider here?
341 e.g local master browsers... no. local master browsers do
342 local master announcements to their domain master. they even
343 use WINS lookup of the domain master if another wins server
344 is being used!
347 else
349 if (AM_MASTER(work))
351 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
352 inet_ntoa(d->bcast_ip),work->work_group));
354 do_announce_host(ANN_LocalMasterAnnouncement,
355 name , 0x00, d->myip,
356 work->work_group, 0x1e, d->bcast_ip,
357 ttl*1000,
358 name, server_type, comment);
360 DEBUG(3,("sending domain announce to %s for %s\n",
361 inet_ntoa(d->bcast_ip),work->work_group));
363 /* XXXX should we do a domain-announce-kill? */
364 if (server_type != 0)
366 if (AM_DOMCTL(work))
368 domain_type |= SV_TYPE_DOMAIN_CTRL;
370 do_announce_host(ANN_DomainAnnouncement,
371 name , 0x00, d->myip,
372 MSBROWSE, 0x01, d->bcast_ip,
373 ttl*1000,
374 work->work_group, server_type ? domain_type : 0,
375 name);
378 else
380 DEBUG(3,("sending host announce to %s for %s(1d)\n",
381 inet_ntoa(d->bcast_ip),work->work_group));
383 do_announce_host(ANN_HostAnnouncement,
384 name , 0x00, d->myip,
385 work->work_group, 0x1d, d->bcast_ip,
386 ttl*1000,
387 name, server_type, comment);
392 /****************************************************************************
393 construct a host announcement unicast
394 **************************************************************************/
395 void announce_host(void)
397 time_t t = time(NULL);
398 struct subnet_record *d;
399 pstring comment;
400 char *my_name;
402 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
404 my_name = *myname ? myname : "NoName";
406 for (d = subnetlist; d; d = d->next)
408 struct work_record *work;
410 if (ip_equal(d->bcast_ip, ipgrp)) continue;
412 for (work = d->workgrouplist; work; work = work->next)
414 uint32 stype = work->ServerType;
415 struct server_record *s;
416 BOOL announce = False;
418 /* must work on the code that does announcements at up to
419 30 seconds later if a master browser sends us a request
420 announce.
423 if (work->needannounce) {
424 /* drop back to a max 3 minute announce - this is to prevent a
425 single lost packet from stuffing things up for too long */
426 work->announce_interval = MIN(work->announce_interval,
427 CHECK_TIME_MIN_HOST_ANNCE*60);
428 work->lastannounce_time = t - (work->announce_interval+1);
431 /* announce every minute at first then progress to every 12 mins */
432 if (work->lastannounce_time &&
433 (t - work->lastannounce_time) < work->announce_interval)
434 continue;
436 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
437 work->announce_interval += 60;
439 work->lastannounce_time = t;
442 if (!d->my_interface) {
443 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
444 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
445 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
449 for (s = work->serverlist; s; s = s->next) {
450 if (strequal(myname, s->serv.name)) {
451 announce = True;
452 break;
456 if (announce)
458 announce_server(d,work,my_name,comment,work->announce_interval,stype);
461 if (work->needannounce)
463 work->needannounce = False;
464 break;
465 /* sorry: can't do too many announces. do some more later */
472 /****************************************************************************
473 announce myself as a master to all other primary domain conrollers.
475 BIG NOTE: this code will remain untested until some kind soul that has access
476 to a couple of windows NT advanced servers runs this version of nmbd for at
477 least 15 minutes.
479 this actually gets done in search_and_sync_workgroups() via the
480 NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
481 name query initiated here. see response_name_query()
482 **************************************************************************/
483 void announce_master(void)
485 struct subnet_record *d;
486 static time_t last=0;
487 time_t t = time(NULL);
488 BOOL am_master = False; /* are we a master of some sort? :-) */
490 if (!last) last = t;
491 if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
492 return;
494 last = t;
496 for (d = subnetlist; d; d = d->next)
498 struct work_record *work;
499 for (work = d->workgrouplist; work; work = work->next)
501 if (AM_MASTER(work))
503 am_master = True;
508 if (!am_master) return; /* only proceed if we are a master browser */
510 for (d = subnetlist; d; d = d->next)
512 struct work_record *work;
513 for (work = d->workgrouplist; work; work = work->next)
515 struct server_record *s;
516 for (s = work->serverlist; s; s = s->next)
518 if (strequal(s->serv.name, myname)) continue;
520 /* all DOMs (which should also be master browsers) */
521 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
523 /* check the existence of a pdc for this workgroup, and if
524 one exists at the specified ip, sync with it and announce
525 ourselves as a master browser to it */
527 if (!*lp_domain_controller() ||
528 !strequal(lp_domain_controller(), s->serv.name))
530 if (!lp_wins_support() && *lp_wins_server())
532 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
533 NAME_QUERY_DOM_SRV_CHK,
534 work->work_group,0x1b,0,0,0,NULL,NULL,
535 False, False, ipzero, ipzero);
537 else
539 struct subnet_record *d2;
540 for (d2 = subnetlist; d2; d2 = d2->next)
542 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
543 NAME_QUERY_DOM_SRV_CHK,
544 work->work_group,0x1b,0,0,0,NULL,NULL,
545 True, False, d2->bcast_ip, d2->bcast_ip);
552 /* now do primary domain controller - the one that's not
553 necessarily in our browse lists, although it ought to be
554 this pdc is the one that we get TOLD about through smb.conf.
555 basically, if it's on a subnet that we know about, it may end
556 up in our browse lists (which is why it's explicitly excluded
557 in the code above) */
559 if (*lp_domain_controller())
561 struct in_addr ip;
562 BOOL bcast = False;
564 ip = *interpret_addr2(lp_domain_controller());
566 if (zero_ip(ip)) {
567 ip = d->bcast_ip;
568 bcast = True;
571 DEBUG(2, ("Searching for DOM %s at %s\n",
572 lp_domain_controller(), inet_ntoa(ip)));
574 /* check the existence of a pdc for this workgroup, and if
575 one exists at the specified ip, sync with it and announce
576 ourselves as a master browser to it */
577 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
578 work->work_group,0x1b,0,0,0,NULL,NULL,
579 bcast, False, ip, ip);