2 Unix SMB/Netbios implementation.
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.
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
32 extern int DEBUGLEVEL
;
33 extern BOOL CanRecurse
;
35 extern struct in_addr ipzero
;
37 extern pstring myname
;
39 extern int ClientDGRAM
;
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
)
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
));
72 CVAL(p
,0) = ANN_AnnouncementRequest
;
75 CVAL(p
,0) = work
->token
; /* flags?? XXXX probably a token*/
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
,
91 int to
, struct in_addr dest_ip
)
96 bzero(outbuf
,sizeof(outbuf
));
98 CVAL(p
,0) = announce_type
;
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
));
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
);
121 struct subnet_record
*d1
;
124 if (!lastrun
) lastrun
= t
;
125 if (t
< lastrun
+ CHECK_TIME_ANNOUNCE_BACKUP
* 60)
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
);
143 /* found one: announce it across all domains */
144 for (d
= subnetlist
; d
; d
= d
->next
)
148 if (AM_DOMCTL(work
)) {
150 } else if (AM_MASTER(work
)) {
156 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
157 inet_ntoa(d
->bcast_ip
),work
->work_group
,
160 bzero(outbuf
,sizeof(outbuf
));
162 CVAL(p
,0) = ANN_GetBackupListReq
;
165 CVAL(p
,0) = 1; /* count? */
166 SIVAL(p
,1,work
->token
); /* workgroup unique key index */
170 send_mailslot_reply(BROWSE_MAILSLOT
,
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
)
194 bzero(outbuf
,sizeof(outbuf
));
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);
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
);
216 p
= skip_string(p
,1);
218 /* send the announcement */
219 send_mailslot_reply(BROWSE_MAILSLOT
,ClientDGRAM
,outbuf
,
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
)
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
);
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
;
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
)
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
)) {
327 announce_server(d
,work
,my_name
,comment
,work
->announce_interval
,stype
);
330 if (work
->needannounce
)
332 work
->needannounce
= False
;
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
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))
364 for (d
= subnetlist
; d
; d
= d
->next
)
366 struct work_record
*work
;
367 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
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())
403 queue_netbios_pkt_wins(d
,ClientNMB
,NMB_QUERY
,
404 NAME_QUERY_MST_SRV_CHK
,
405 work
->work_group
,0x1b,0,0,
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())
435 ip
= *interpret_addr2(lp_domain_controller());
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,