2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1996
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
31 extern int ClientDGRAM
;
33 #define TEST_CODE /* want to debug unknown browse packets */
35 extern int DEBUGLEVEL
;
37 extern BOOL CanRecurse
;
39 extern pstring myname
;
42 extern int ClientDGRAM
;
44 extern struct in_addr ipzero
;
46 extern int workgroup_count
; /* total number of workgroups we know about */
48 /* this is our domain/workgroup/server database */
49 extern struct subnet_record
*subnetlist
;
51 extern int updatecount
;
53 /* backup request types: which servers are to be included */
54 #define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
55 #define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL )
57 extern time_t StartupTime
;
59 extern BOOL updatedlists
;
61 /****************************************************************************
62 tell a server to become a backup browser
63 state - 0x01 become backup instead of master
64 - 0x02 remove all entries in browse list and become non-master
65 - 0x04 stop master browser service altogether. NT ignores this
66 **************************************************************************/
67 void reset_server(char *name
, int state
, struct in_addr ip
)
72 bzero(outbuf
,sizeof(outbuf
));
75 CVAL(p
,0) = ANN_ResetBrowserState
;
79 DEBUG(2,("sending reset to %s %s of state %d\n",
80 name
,inet_ntoa(ip
),state
));
82 send_mailslot_reply(BROWSE_MAILSLOT
,ClientDGRAM
,outbuf
,PTR_DIFF(p
,outbuf
),
83 myname
,name
,0x20,0x1d,ip
,*iface_ip(ip
));
87 /****************************************************************************
88 tell a server to become a backup browser
89 **************************************************************************/
90 void tell_become_backup(void)
92 /* XXXX note: this function is currently unsuitable for use, as it
93 does not properly check that a server is in a fit state to become
94 a backup browser before asking it to be one.
97 struct subnet_record
*d
;
98 for (d
= subnetlist
; d
; d
= d
->next
)
100 struct work_record
*work
;
101 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
103 struct server_record
*s
;
107 for (s
= work
->serverlist
; s
; s
= s
->next
)
109 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) continue;
113 if (strequal(myname
, s
->serv
.name
)) continue;
115 if (s
->serv
.type
& SV_TYPE_BACKUP_BROWSER
) {
120 if (s
->serv
.type
& SV_TYPE_MASTER_BROWSER
) continue;
122 if (!(s
->serv
.type
& SV_TYPE_POTENTIAL_BROWSER
)) continue;
124 DEBUG(3,("num servers: %d num backups: %d\n",
125 num_servers
, num_backups
));
127 /* make first server a backup server. thereafter make every
128 tenth server a backup server */
129 if (num_backups
!= 0 && (num_servers
+9) / num_backups
> 10)
134 DEBUG(2,("sending become backup to %s %s for %s\n",
135 s
->serv
.name
, inet_ntoa(d
->bcast_ip
),
138 /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
139 do_announce_request(s
->serv
.name
, work
->work_group
,
140 ANN_BecomeBackup
, 0x20, 0x1e, d
->bcast_ip
);
147 /*******************************************************************
148 same context: scope. should check name_type as well, and makes sure
149 we don't process messages from ourselves
150 ******************************************************************/
151 BOOL
same_context(struct dgram_packet
*dgram
)
153 if (!strequal(dgram
->dest_name
.scope
,scope
)) return(True
);
154 if ( strequal(dgram
->source_name
.name
,myname
)) return(True
);
160 /*******************************************************************
161 process a domain announcement frame
163 Announce frames come in 3 types. Servers send host announcements
164 (command=1) to let the master browswer know they are
165 available. Master browsers send local master announcements
166 (command=15) to let other masters and backups that they are the
167 master. They also send domain announcements (command=12) to register
170 The comment field of domain announcements contains the master
171 browser name. The servertype is used by NetServerEnum to select
172 resources. We just have to pass it to smbd (via browser.dat) and let
173 the client choose using bit masks.
174 ******************************************************************/
175 static void process_announce(struct packet_struct
*p
,uint16 command
,char *buf
)
177 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
178 struct in_addr ip
= dgram
->header
.source_ip
;
179 struct subnet_record
*d
= find_subnet(ip
);
180 int update_count
= CVAL(buf
,0);
182 int ttl
= IVAL(buf
,1)/1000;
184 int osmajor
=CVAL(buf
,21);
185 int osminor
=CVAL(buf
,22);
186 uint32 servertype
= IVAL(buf
,23);
187 uint32 browse_type
= CVAL(buf
,27);
188 uint32 browse_sig
= CVAL(buf
,29);
189 char *comment
= buf
+31;
191 struct work_record
*work
;
193 char *serv_name
= dgram
->source_name
.name
;
198 DEBUG(4,("Announce(%d) %s(%x)",command
,name
,name
[15]));
199 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
200 namestr(&dgram
->dest_name
),update_count
,ttl
,osmajor
,osminor
,
201 servertype
,browse_type
,browse_sig
,comment
));
205 if (dgram
->dest_name
.name_type
== 0 && command
== ANN_HostAnnouncement
)
207 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
211 if (command
== ANN_DomainAnnouncement
&&
212 ((!strequal(dgram
->dest_name
.name
, MSBROWSE
)) ||
213 dgram
->dest_name
.name_type
!= 0x1))
215 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
216 command
, inet_ntoa(ip
), namestr(&dgram
->dest_name
)));
220 if (!strequal(dgram
->dest_name
.scope
,scope
)) return;
222 if (command
== ANN_DomainAnnouncement
) {
223 /* XXXX if we are a master browser for the workgroup work_name,
224 then there is a local subnet configuration problem. only
225 we should be sending out such domain announcements, because
226 as the master browser, that is our job.
228 stop being a master browser, and force an election. this will
229 sort out the network problem. hopefully.
235 work_name
= dgram
->dest_name
.name
;
238 /* we need some way of finding out about new workgroups
239 that appear to be sending packets to us. The name_type checks make
240 sure we don't add host names as workgroups */
241 if (command
== ANN_HostAnnouncement
&&
242 (dgram
->dest_name
.name_type
== 0x1d ||
243 dgram
->dest_name
.name_type
== 0x1e))
246 if (!(work
= find_workgroupstruct(d
, work_name
,add
)))
249 DEBUG(4, ("workgroup %s on %s\n", work
->work_group
, serv_name
));
253 /* add them to our browse list, and update the browse.dat file */
254 add_server_entry(d
,work
,name
,servertype
,ttl
,comment
,True
);
258 /* the tell become backup code is broken, no great harm is done by
260 tell_become_backup();
263 /* get the local_only browse list from the local master and add it
265 if (command
== ANN_LocalMasterAnnouncement
)
267 add_browser_entry(serv_name
,dgram
->dest_name
.name_type
,
268 work
->work_group
,30,ip
,True
);
272 /*******************************************************************
273 process a master announcement frame
274 ******************************************************************/
275 static void process_master_announce(struct packet_struct
*p
,char *buf
)
277 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
278 struct in_addr ip
= dgram
->header
.source_ip
;
279 struct subnet_record
*d
= find_subnet(ip
);
280 struct subnet_record
*mydomain
= find_subnet(*iface_bcast(ip
));
282 struct work_record
*work
;
285 DEBUG(3,("Master Announce from %s (%s)\n",name
,inet_ntoa(ip
)));
287 if (same_context(dgram
)) return;
289 if (!d
|| !mydomain
) return;
291 if (!lp_domain_master()) return;
293 for (work
= mydomain
->workgrouplist
; work
; work
= work
->next
)
297 /* merge browse lists with them */
298 add_browser_entry(name
,0x1b, work
->work_group
,30,ip
,True
);
303 /*******************************************************************
304 process a receive backup list request
306 we receive a list of servers, and we attempt to locate them all on
307 our local subnet, and sync browse lists with them on the workgroup
308 they are said to be in.
310 XXXX NOTE: this function is in overdrive. it should not really do
311 half of what it actually does (it should pick _one_ name from the
312 list received and sync with it at regular intervals, rather than
313 sync with them all only once!)
315 ******************************************************************/
316 static void process_rcv_backup_list(struct packet_struct
*p
,char *buf
)
318 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
319 struct in_addr ip
= dgram
->header
.source_ip
;
320 int count
= CVAL(buf
,0);
321 uint32 info
= IVAL(buf
,1); /* XXXX caller's incremental info */
324 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
325 namestr(&dgram
->dest_name
), inet_ntoa(ip
),
328 if (same_context(dgram
)) return;
330 if (count
<= 0) return;
332 /* go through the list of servers attempting to sync browse lists */
333 for (buf1
= buf
+5; *buf1
&& count
; buf1
= skip_string(buf1
, 1), --count
)
335 struct in_addr back_ip
;
336 /* struct subnet_record *d; */
338 DEBUG(4,("Searching for backup browser %s at %s...\n",
339 buf1
, inet_ntoa(ip
)));
341 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
342 approach is to use reply_name_query functionality to find the name */
344 back_ip
= *interpret_addr2(buf1
);
346 if (zero_ip(back_ip
))
348 DEBUG(4,("Failed to find backup browser server using DNS\n"));
352 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip
)));
353 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
356 /* XXXX function needs work */
359 if ((d
= find_subnet(back_ip
)))
361 struct subnet_record
*d1
;
362 for (d1
= subnetlist
; d1
; d1
= d1
->next
)
364 struct work_record
*work
;
365 for (work
= d1
->workgrouplist
; work
; work
= work
->next
)
367 if (work
->token
== 0 /* token */)
369 queue_netbios_packet(d1
,ClientNMB
,NMB_QUERY
,NAME_QUERY_SRV_CHK
,
370 work
->work_group
,0x1d,
372 False
,False
,back_ip
,back_ip
);
383 /****************************************************************************
384 send a backup list response.
385 **************************************************************************/
386 static void send_backup_list(char *work_name
, struct nmb_name
*src_name
,
387 int token
, uint32 info
,
388 int name_type
, struct in_addr ip
)
391 char *p
, *countptr
, *nameptr
;
393 char *theirname
= src_name
->name
;
395 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
396 work_name
, inet_ntoa(ip
),
397 myname
,0x0,theirname
,0x0));
399 if (name_type
== 0x1d)
401 DEBUG(4,("master browsers: "));
403 else if (name_type
== 0x1b)
405 DEBUG(4,("domain controllers: "));
409 DEBUG(0,("backup request for unknown type %0x\n", name_type
));
413 bzero(outbuf
,sizeof(outbuf
));
416 CVAL(p
,0) = ANN_GetBackupListResp
; /* backup list response */
421 SIVAL(p
,1,info
); /* the sender's unique info */
429 for (d
= subnetlist
; d
; d
= d
->next
)
431 struct work_record
*work
;
433 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
435 struct server_record
*s
;
437 if (!strequal(work
->work_group
, work_name
)) continue;
439 for (s
= work
->serverlist
; s
; s
= s
->next
)
444 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) continue;
446 for (n
= nameptr
; n
< p
; n
= skip_string(n
, 1))
448 if (strequal(n
, s
->serv
.name
)) found
= True
;
451 if (found
) continue; /* exclude names already added */
453 /* workgroup request: include all backup browsers in the list */
454 /* domain request: include all domain members in the list */
456 if ((name_type
== 0x1d && (s
->serv
.type
& MASTER_TYPE
)) ||
457 (name_type
== 0x1b && (s
->serv
.type
& DOMCTL_TYPE
)))
459 DEBUG(4, ("%s ", s
->serv
.name
));
462 strcpy(p
,s
->serv
.name
);
464 p
= skip_string(p
,1);
475 p
= skip_string(p
,1);
479 DEBUG(4, ("none\n"));
483 DEBUG(4, (" - count %d\n", count
));
486 CVAL(countptr
, 0) = count
;
489 int len
= PTR_DIFF(p
, outbuf
);
490 debug_browse_data(outbuf
, len
);
492 send_mailslot_reply(BROWSE_MAILSLOT
,ClientDGRAM
,outbuf
,PTR_DIFF(p
,outbuf
),
493 myname
,theirname
,0x0,0x0,ip
,*iface_ip(ip
));
497 /*******************************************************************
498 process a send backup list request
500 A client sends a backup list request to ask for a list of servers on
501 the net that maintain server lists for a domain. A server is then
502 chosen from this list to send NetServerEnum commands to to list
505 Currently samba only sends back one name in the backup list, its
506 own. For larger nets we'll have to add backups and send "become
507 backup" requests occasionally.
508 ******************************************************************/
509 static void process_send_backup_list(struct packet_struct
*p
,char *buf
)
511 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
512 struct in_addr ip
= dgram
->header
.source_ip
;
513 struct subnet_record
*d
;
514 struct work_record
*work
;
516 int token
= CVAL(buf
,0); /* sender's key index for the workgroup */
517 uint32 info
= IVAL(buf
,1); /* XXXX don't know: some sort of info */
518 int name_type
= dgram
->dest_name
.name_type
;
520 if (same_context(dgram
)) return;
522 if (name_type
!= 0x1b && name_type
!= 0x1d) {
523 DEBUG(0,("backup request to wrong type %d from %s\n",
524 name_type
,inet_ntoa(ip
)));
528 for (d
= subnetlist
; d
; d
= d
->next
)
530 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
532 if (strequal(work
->work_group
, dgram
->dest_name
.name
))
534 DEBUG(2,("sending backup list to %s %s id=%x\n",
535 namestr(&dgram
->dest_name
),inet_ntoa(ip
),info
));
537 send_backup_list(work
->work_group
,&dgram
->source_name
,
538 token
,info
,name_type
,ip
);
546 /*******************************************************************
547 process a reset browser state
550 0x1 - stop being a master browser and become a backup browser.
551 0x2 - discard browse lists, stop being a master browser, try again.
552 0x4 - stop being a master browser forever. no way. ain't gonna.
554 ******************************************************************/
555 static void process_reset_browser(struct packet_struct
*p
,char *buf
)
557 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
558 int state
= CVAL(buf
,0);
560 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
561 namestr(&dgram
->dest_name
), state
));
563 /* stop being a master but still deal with being a backup browser */
566 struct subnet_record
*d
;
567 for (d
= subnetlist
; d
; d
= d
->next
)
569 struct work_record
*work
;
570 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
574 become_nonmaster(d
,work
,SV_TYPE_DOMAIN_MASTER
|SV_TYPE_MASTER_BROWSER
);
580 /* XXXX documentation inconsistency: the above description does not
581 exactly tally with what is implemented for state & 0x2
584 /* totally delete all servers and start afresh */
587 struct subnet_record
*d
;
588 for (d
= subnetlist
; d
; d
= d
->next
)
590 struct work_record
*work
;
591 for (work
=d
->workgrouplist
;work
;work
=remove_workgroup(d
,work
,True
));
593 add_my_subnets(lp_workgroup());
596 /* stop browsing altogether. i don't think this is a good idea! */
599 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
603 /*******************************************************************
604 process a announcement request
606 clients send these when they want everyone to send an announcement
607 immediately. This can cause quite a storm of packets!
608 ******************************************************************/
609 static void process_announce_request(struct packet_struct
*p
,char *buf
)
611 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
612 struct work_record
*work
;
613 struct in_addr ip
= dgram
->header
.source_ip
;
614 struct subnet_record
*d
= find_subnet(ip
);
615 int token
= CVAL(buf
,0);
620 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
621 name
,namestr(&dgram
->dest_name
), token
));
623 if (strequal(dgram
->source_name
.name
,myname
)) return;
625 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
626 this workgroup before announcing, particularly as we only
627 respond on local interfaces anyway.
629 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
634 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
636 /* XXXX BUG: the destination name type should also be checked,
637 not just the name. e.g if the name is WORKGROUP(0x1d) then
638 we should only respond if we own that name */
640 if (strequal(dgram
->dest_name
.name
,work
->work_group
))
642 work
->needannounce
= True
;
649 /****************************************************************************
650 process a browse frame
651 ****************************************************************************/
652 void process_browse_packet(struct packet_struct
*p
,char *buf
,int len
)
654 int command
= CVAL(buf
,0);
657 case ANN_HostAnnouncement
:
658 case ANN_DomainAnnouncement
:
659 case ANN_LocalMasterAnnouncement
:
661 debug_browse_data(buf
, len
);
662 process_announce(p
,command
,buf
+1);
666 case ANN_AnnouncementRequest
:
668 process_announce_request(p
,buf
+1);
674 process_election(p
,buf
+1);
678 case ANN_GetBackupListReq
:
680 debug_browse_data(buf
, len
);
681 process_send_backup_list(p
,buf
+1);
685 case ANN_GetBackupListResp
:
687 debug_browse_data(buf
, len
);
688 process_rcv_backup_list(p
, buf
+1);
692 case ANN_ResetBrowserState
:
694 process_reset_browser(p
, buf
+1);
698 case ANN_MasterAnnouncement
:
700 process_master_announce(p
,buf
+1);
706 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
707 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
708 command
, namestr(&dgram
->source_name
),
709 inet_ntoa(p
->ip
), namestr(&dgram
->dest_name
)));