patch to fix NetServerEnum with multiple workgroup lists kindly supplied.
[Samba.git] / source / nameannounce.c
blob5163c4aea9ad1c627cde2cb7eeb5a7ff8e4e976d
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 /* what server type are we currently */
53 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
55 /****************************************************************************
56 send a announce request to the local net
57 **************************************************************************/
58 void announce_request(struct work_record *work, struct in_addr ip)
60 pstring outbuf;
61 char *p;
63 if (!work) return;
65 work->needannounce = True;
67 DEBUG(2,("sending announce request to %s for workgroup %s\n",
68 inet_ntoa(ip),work->work_group));
70 bzero(outbuf,sizeof(outbuf));
71 p = outbuf;
72 CVAL(p,0) = ANN_AnnouncementRequest;
73 p++;
75 CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
76 p++;
77 StrnCpy(p,myname,16);
78 strupper(p);
79 p = skip_string(p,1);
81 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
82 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
86 /****************************************************************************
87 request an announcement
88 **************************************************************************/
89 void do_announce_request(char *info, char *to_name, int announce_type,
90 int from,
91 int to, struct in_addr dest_ip)
93 pstring outbuf;
94 char *p;
96 bzero(outbuf,sizeof(outbuf));
97 p = outbuf;
98 CVAL(p,0) = announce_type;
99 p++;
101 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
102 announce_type, info, inet_ntoa(dest_ip),to_name,to));
104 StrnCpy(p,info,16);
105 strupper(p);
106 p = skip_string(p,1);
108 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
109 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
112 /****************************************************************************
113 construct a host announcement unicast
114 **************************************************************************/
115 void announce_backup(void)
117 static time_t lastrun = 0;
118 time_t t = time(NULL);
119 pstring outbuf;
120 char *p;
121 struct subnet_record *d1;
122 int tok;
124 if (!lastrun) lastrun = t;
125 if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
126 return;
127 lastrun = t;
129 for (tok = 0; tok <= workgroup_count; tok++)
131 for (d1 = subnetlist; d1; d1 = d1->next)
133 struct work_record *work;
134 struct subnet_record *d;
136 /* search for unique workgroup: only the name matters */
137 for (work = d1->workgrouplist;
138 work && (tok != work->token);
139 work = work->next);
141 if (!work) continue;
143 /* found one: announce it across all domains */
144 for (d = subnetlist; d; d = d->next)
146 int type=0;
148 if (AM_DOMCTL(work)) {
149 type = 0x1b;
150 } else if (AM_MASTER(work)) {
151 type = 0x1d;
152 } else {
153 continue;
156 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
157 inet_ntoa(d->bcast_ip),work->work_group,
158 work->token));
160 bzero(outbuf,sizeof(outbuf));
161 p = outbuf;
162 CVAL(p,0) = ANN_GetBackupListReq;
163 p++;
165 CVAL(p,0) = 1; /* count? */
166 SIVAL(p,1,work->token); /* workgroup unique key index */
167 p += 5;
168 p++;
170 send_mailslot_reply(BROWSE_MAILSLOT,
171 ClientDGRAM,outbuf,
172 PTR_DIFF(p,outbuf),
173 myname, work->work_group,
174 0x0,type,d->bcast_ip,
175 *iface_ip(d->bcast_ip));
182 /****************************************************************************
183 send a host announcement packet
184 **************************************************************************/
185 void do_announce_host(int command,
186 char *from_name, int from_type, struct in_addr from_ip,
187 char *to_name , int to_type , struct in_addr to_ip,
188 int updatecount, time_t announce_interval,
189 char *server_name, int server_type, char *server_comment)
191 pstring outbuf;
192 char *p;
194 bzero(outbuf,sizeof(outbuf));
195 p = outbuf+1;
197 /* command type */
198 CVAL(outbuf,0) = command;
200 /* announcement parameters */
201 CVAL(p,0) = updatecount;
202 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
204 StrnCpy(p+5,server_name,16);
205 strupper(p+5);
207 CVAL(p,21) = 2; /* major version */
208 CVAL(p,22) = 2; /* minor version */
210 SIVAL(p,23,server_type);
211 SSVAL(p,27,0xaa55); /* browse signature */
212 SSVAL(p,29,1); /* browse version */
214 strcpy(p+31,server_comment);
215 p += 31;
216 p = skip_string(p,1);
218 /* send the announcement */
219 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
220 PTR_DIFF(p,outbuf),
221 from_name, to_name,
222 from_type, to_type,
223 to_ip, from_ip);
227 /****************************************************************************
228 announce a server entry
229 ****************************************************************************/
230 void announce_server(struct subnet_record *d, struct work_record *work,
231 char *name, char *comment, time_t ttl, int server_type)
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 updatecount, ttl*1000,
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 work->work_group, 0x00, d->myip,
252 MSBROWSE , 0x01, d->bcast_ip,
253 updatecount, ttl*1000,
254 name, server_type ? SV_TYPE_DOMAIN_ENUM : 0, comment);
257 else
259 DEBUG(3,("sending host announce to %s for %s(1d)\n",
260 inet_ntoa(d->bcast_ip),work->work_group));
262 do_announce_host(ANN_HostAnnouncement,
263 name , 0x00, d->myip,
264 work->work_group, 0x1d, d->bcast_ip,
265 updatecount, ttl*1000,
266 name, server_type, comment);
270 /****************************************************************************
271 construct a host announcement unicast
272 **************************************************************************/
273 void announce_host(void)
275 time_t t = time(NULL);
276 struct subnet_record *d;
277 pstring comment;
278 char *my_name;
280 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
282 my_name = *myname ? myname : "NoName";
284 for (d = subnetlist; d; d = d->next)
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 if (work->needannounce) {
295 /* drop back to a max 3 minute announce - this is to prevent a
296 single lost packet from stuffing things up for too long */
297 work->announce_interval = MIN(work->announce_interval,
298 CHECK_TIME_MIN_HOST_ANNCE*60);
299 work->lastannounce_time = t - (work->announce_interval+1);
302 /* announce every minute at first then progress to every 12 mins */
303 if (work->lastannounce_time &&
304 (t - work->lastannounce_time) < work->announce_interval)
305 continue;
307 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
308 work->announce_interval += 60;
310 work->lastannounce_time = t;
312 if (!d->my_interface) {
313 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
314 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
315 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
318 for (s = work->serverlist; s; s = s->next) {
319 if (strequal(myname, s->serv.name)) {
320 announce = True;
321 break;
325 if (announce)
327 announce_server(d,work,my_name,comment,work->announce_interval,stype);
330 if (work->needannounce)
332 work->needannounce = False;
333 break;
334 /* sorry: can't do too many announces. do some more later */
341 /****************************************************************************
342 announce myself as a master to all other primary domain conrollers.
344 BIG NOTE: this code will remain untested until some kind soul that has access
345 to a couple of windows NT advanced servers runs this version of nmbd for at
346 least 15 minutes.
348 this actually gets done in search_and_sync_workgroups() via the
349 NAME_QUERY_MST_SRV_CHK command, if there is a response from the
350 name query initiated here. see response_name_query()
351 **************************************************************************/
352 void announce_master(void)
354 struct subnet_record *d;
355 static time_t last=0;
356 time_t t = time(NULL);
357 BOOL am_master = False; /* are we a master of some sort? :-) */
359 if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60))
360 return;
362 last = t;
364 for (d = subnetlist; d; d = d->next)
366 struct work_record *work;
367 for (work = d->workgrouplist; work; work = work->next)
369 if (AM_MASTER(work))
371 am_master = True;
376 if (!am_master) return; /* only proceed if we are a master browser */
378 for (d = subnetlist; d; d = d->next)
380 struct work_record *work;
381 for (work = d->workgrouplist; work; work = work->next)
383 struct server_record *s;
384 for (s = work->serverlist; s; s = s->next)
386 if (strequal(s->serv.name, myname)) continue;
388 /* all PDCs (which should also be master browsers) */
389 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
391 /* check the existence of a pdc for this workgroup, and if
392 one exists at the specified ip, sync with it and announce
393 ourselves as a master browser to it */
395 if (!*lp_domain_controller() ||
396 !strequal(lp_domain_controller(), s->serv.name))
398 if (!lp_wins_support() && *lp_wins_server())
400 struct in_addr ip;
401 ip = ipzero;
403 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
404 NAME_QUERY_MST_SRV_CHK,
405 work->work_group,0x1b,0,0,
406 False, False, ip);
408 else
410 struct subnet_record *d2;
411 for (d2 = subnetlist; d2; d2 = d2->next)
413 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
414 NAME_QUERY_MST_SRV_CHK,
415 work->work_group,0x1b,0,0,
416 True, False, d2->bcast_ip);
423 /* now do primary domain controller - the one that's not
424 necessarily in our browse lists, although it ought to be
425 this pdc is the one that we get TOLD about through smb.conf.
426 basically, if it's on a subnet that we know about, it may end
427 up in our browse lists (which is why it's explicitly excluded
428 in the code above) */
430 if (*lp_domain_controller())
432 struct in_addr ip;
433 BOOL bcast = False;
435 ip = *interpret_addr2(lp_domain_controller());
437 if (zero_ip(ip)) {
438 ip = d->bcast_ip;
439 bcast = True;
442 DEBUG(2, ("Searching for PDC %s at %s\n",
443 lp_domain_controller(), inet_ntoa(ip)));
445 /* check the existence of a pdc for this workgroup, and if
446 one exists at the specified ip, sync with it and announce
447 ourselves as a master browser to it */
448 queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_MST_SRV_CHK,
449 work->work_group,0x1b, 0, 0,
450 bcast, False, ip);