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"));
355 /* XXXX function needs work */
358 if ((d
= find_subnet(back_ip
)))
360 struct subnet_record
*d1
;
361 for (d1
= subnetlist
; d1
; d1
= d1
->next
)
363 struct work_record
*work
;
364 for (work
= d1
->workgrouplist
; work
; work
= work
->next
)
366 if (work
->token
== 0 /* token */)
368 queue_netbios_packet(d1
,ClientNMB
,NMB_QUERY
,NAME_QUERY_SRV_CHK
,
369 work
->work_group
,0x1d,
371 False
,False
,back_ip
,back_ip
);
381 /****************************************************************************
382 send a backup list response.
383 **************************************************************************/
384 static void send_backup_list(char *work_name
, struct nmb_name
*src_name
,
385 int token
, uint32 info
,
386 int name_type
, struct in_addr ip
)
389 char *p
, *countptr
, *nameptr
;
391 char *theirname
= src_name
->name
;
393 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
394 work_name
, inet_ntoa(ip
),
395 myname
,0x0,theirname
,0x0));
397 if (name_type
== 0x1d)
399 DEBUG(4,("master browsers: "));
401 else if (name_type
== 0x1b)
403 DEBUG(4,("domain controllers: "));
407 DEBUG(0,("backup request for unknown type %0x\n", name_type
));
411 bzero(outbuf
,sizeof(outbuf
));
414 CVAL(p
,0) = ANN_GetBackupListResp
; /* backup list response */
419 SIVAL(p
,1,info
); /* the sender's unique info */
427 for (d
= subnetlist
; d
; d
= d
->next
)
429 struct work_record
*work
;
431 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
433 struct server_record
*s
;
435 if (!strequal(work
->work_group
, work_name
)) continue;
437 for (s
= work
->serverlist
; s
; s
= s
->next
)
442 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) continue;
444 for (n
= nameptr
; n
< p
; n
= skip_string(n
, 1))
446 if (strequal(n
, s
->serv
.name
)) found
= True
;
449 if (found
) continue; /* exclude names already added */
451 /* workgroup request: include all backup browsers in the list */
452 /* domain request: include all domain members in the list */
454 if ((name_type
== 0x1d && (s
->serv
.type
& MASTER_TYPE
)) ||
455 (name_type
== 0x1b && (s
->serv
.type
& DOMCTL_TYPE
)))
457 DEBUG(4, ("%s ", s
->serv
.name
));
460 strcpy(p
,s
->serv
.name
);
462 p
= skip_string(p
,1);
473 p
= skip_string(p
,1);
477 DEBUG(4, ("none\n"));
481 DEBUG(4, (" - count %d\n", count
));
484 CVAL(countptr
, 0) = count
;
487 int len
= PTR_DIFF(p
, outbuf
);
488 debug_browse_data(outbuf
, len
);
490 send_mailslot_reply(BROWSE_MAILSLOT
,ClientDGRAM
,outbuf
,PTR_DIFF(p
,outbuf
),
491 myname
,theirname
,0x0,0x0,ip
,*iface_ip(ip
));
495 /*******************************************************************
496 process a send backup list request
498 A client sends a backup list request to ask for a list of servers on
499 the net that maintain server lists for a domain. A server is then
500 chosen from this list to send NetServerEnum commands to to list
503 Currently samba only sends back one name in the backup list, its
504 own. For larger nets we'll have to add backups and send "become
505 backup" requests occasionally.
506 ******************************************************************/
507 static void process_send_backup_list(struct packet_struct
*p
,char *buf
)
509 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
510 struct in_addr ip
= dgram
->header
.source_ip
;
511 struct subnet_record
*d
;
512 struct work_record
*work
;
514 int token
= CVAL(buf
,0); /* sender's key index for the workgroup */
515 uint32 info
= IVAL(buf
,1); /* XXXX don't know: some sort of info */
516 int name_type
= dgram
->dest_name
.name_type
;
518 if (same_context(dgram
)) return;
520 if (name_type
!= 0x1b && name_type
!= 0x1d) {
521 DEBUG(0,("backup request to wrong type %d from %s\n",
522 name_type
,inet_ntoa(ip
)));
526 for (d
= subnetlist
; d
; d
= d
->next
)
528 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
530 if (strequal(work
->work_group
, dgram
->dest_name
.name
))
532 DEBUG(2,("sending backup list to %s %s id=%x\n",
533 namestr(&dgram
->dest_name
),inet_ntoa(ip
),info
));
535 send_backup_list(work
->work_group
,&dgram
->source_name
,
536 token
,info
,name_type
,ip
);
544 /*******************************************************************
545 process a reset browser state
548 0x1 - stop being a master browser and become a backup browser.
549 0x2 - discard browse lists, stop being a master browser, try again.
550 0x4 - stop being a master browser forever. no way. ain't gonna.
552 ******************************************************************/
553 static void process_reset_browser(struct packet_struct
*p
,char *buf
)
555 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
556 int state
= CVAL(buf
,0);
558 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
559 namestr(&dgram
->dest_name
), state
));
561 /* stop being a master but still deal with being a backup browser */
564 struct subnet_record
*d
;
565 for (d
= subnetlist
; d
; d
= d
->next
)
567 struct work_record
*work
;
568 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
572 become_nonmaster(d
,work
,SV_TYPE_DOMAIN_MASTER
|SV_TYPE_MASTER_BROWSER
);
578 /* XXXX documentation inconsistency: the above description does not
579 exactly tally with what is implemented for state & 0x2
582 /* totally delete all servers and start afresh */
585 struct subnet_record
*d
;
586 for (d
= subnetlist
; d
; d
= d
->next
)
588 struct work_record
*work
;
589 for (work
=d
->workgrouplist
;work
;work
=remove_workgroup(d
,work
,True
));
591 add_my_subnets(lp_workgroup());
594 /* stop browsing altogether. i don't think this is a good idea! */
597 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
601 /*******************************************************************
602 process a announcement request
604 clients send these when they want everyone to send an announcement
605 immediately. This can cause quite a storm of packets!
606 ******************************************************************/
607 static void process_announce_request(struct packet_struct
*p
,char *buf
)
609 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
610 struct work_record
*work
;
611 struct in_addr ip
= dgram
->header
.source_ip
;
612 struct subnet_record
*d
= find_subnet(ip
);
613 int token
= CVAL(buf
,0);
618 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
619 name
,namestr(&dgram
->dest_name
), token
));
621 if (strequal(dgram
->source_name
.name
,myname
)) return;
623 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
624 this workgroup before announcing, particularly as we only
625 respond on local interfaces anyway.
627 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
632 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
634 /* XXXX BUG: the destination name type should also be checked,
635 not just the name. e.g if the name is WORKGROUP(0x1d) then
636 we should only respond if we own that name */
638 if (strequal(dgram
->dest_name
.name
,work
->work_group
))
640 work
->needannounce
= True
;
647 /****************************************************************************
648 process a browse frame
649 ****************************************************************************/
650 void process_browse_packet(struct packet_struct
*p
,char *buf
,int len
)
652 int command
= CVAL(buf
,0);
655 case ANN_HostAnnouncement
:
656 case ANN_DomainAnnouncement
:
657 case ANN_LocalMasterAnnouncement
:
659 debug_browse_data(buf
, len
);
660 process_announce(p
,command
,buf
+1);
664 case ANN_AnnouncementRequest
:
666 process_announce_request(p
,buf
+1);
672 process_election(p
,buf
+1);
676 case ANN_GetBackupListReq
:
678 debug_browse_data(buf
, len
);
679 process_send_backup_list(p
,buf
+1);
683 case ANN_GetBackupListResp
:
685 debug_browse_data(buf
, len
);
686 process_rcv_backup_list(p
, buf
+1);
690 case ANN_ResetBrowserState
:
692 process_reset_browser(p
, buf
+1);
696 case ANN_MasterAnnouncement
:
698 process_master_announce(p
,buf
+1);
704 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
705 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
706 command
, namestr(&dgram
->source_name
),
707 inet_ntoa(p
->ip
), namestr(&dgram
->dest_name
)));