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 /* machine comment for host announcements */
52 extern pstring ServerComment
;
54 extern int updatecount
;
56 /* what server type are we currently */
57 #define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
58 SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX |\
59 SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
61 /* backup request types: which servers are to be included */
62 #define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
63 #define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL )
65 extern time_t StartupTime
;
67 extern BOOL updatedlists
;
69 /****************************************************************************
70 tell a server to become a backup browser
71 state - 0x01 become backup instead of master
72 - 0x02 remove all entries in browse list and become non-master
73 - 0x04 stop master browser service altogether. NT ignores this
74 **************************************************************************/
75 void reset_server(char *name
, int state
, struct in_addr ip
)
80 bzero(outbuf
,sizeof(outbuf
));
83 CVAL(p
,0) = ANN_ResetBrowserState
;
87 DEBUG(2,("sending reset to %s %s of state %d\n",
88 name
,inet_ntoa(ip
),state
));
90 send_mailslot_reply(BROWSE_MAILSLOT
,ClientDGRAM
,outbuf
,PTR_DIFF(p
,outbuf
),
91 myname
,name
,0x20,0x1d,ip
,*iface_ip(ip
));
95 /****************************************************************************
96 tell a server to become a backup browser
97 **************************************************************************/
98 void tell_become_backup(void)
100 /* XXXX note: this function is currently unsuitable for use, as it
101 does not properly check that a server is in a fit state to become
102 a backup browser before asking it to be one.
105 struct subnet_record
*d
;
106 for (d
= subnetlist
; d
; d
= d
->next
)
108 struct work_record
*work
;
109 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
111 struct server_record
*s
;
115 for (s
= work
->serverlist
; s
; s
= s
->next
)
117 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) continue;
121 if (strequal(myname
, s
->serv
.name
)) continue;
123 if (s
->serv
.type
& SV_TYPE_BACKUP_BROWSER
) {
128 if (s
->serv
.type
& SV_TYPE_MASTER_BROWSER
) continue;
130 if (!(s
->serv
.type
& SV_TYPE_POTENTIAL_BROWSER
)) continue;
132 DEBUG(3,("num servers: %d num backups: %d\n",
133 num_servers
, num_backups
));
135 /* make first server a backup server. thereafter make every
136 tenth server a backup server */
137 if (num_backups
!= 0 && (num_servers
+9) / num_backups
> 10)
142 DEBUG(2,("sending become backup to %s %s for %s\n",
143 s
->serv
.name
, inet_ntoa(d
->bcast_ip
),
146 /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
147 do_announce_request(s
->serv
.name
, work
->work_group
,
148 ANN_BecomeBackup
, 0x20, 0x1e, d
->bcast_ip
);
155 /*******************************************************************
156 same context: scope. should check name_type as well, and makes sure
157 we don't process messages from ourselves
158 ******************************************************************/
159 BOOL
same_context(struct dgram_packet
*dgram
)
161 if (!strequal(dgram
->dest_name
.scope
,scope
)) return(True
);
162 if ( strequal(dgram
->source_name
.name
,myname
)) return(True
);
168 /*******************************************************************
169 am I listening on a name. XXXX check the type of name as well.
170 ******************************************************************/
171 BOOL
listening_name(struct work_record
*work
, struct nmb_name
*n
)
173 if (strequal(n
->name
,myname
) ||
174 strequal(n
->name
,work
->work_group
) ||
175 strequal(n
->name
,MSBROWSE
))
184 /*******************************************************************
185 process a domain announcement frame
187 Announce frames come in 3 types. Servers send host announcements
188 (command=1) to let the master browswer know they are
189 available. Master browsers send local master announcements
190 (command=15) to let other masters and backups that they are the
191 master. They also send domain announcements (command=12) to register
194 The comment field of domain announcements contains the master
195 browser name. The servertype is used by NetServerEnum to select
196 resources. We just have to pass it to smbd (via browser.dat) and let
197 the client choose using bit masks.
198 ******************************************************************/
199 static void process_announce(struct packet_struct
*p
,uint16 command
,char *buf
)
201 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
202 struct in_addr ip
= dgram
->header
.source_ip
;
203 struct subnet_record
*d
= find_subnet(ip
);
204 int update_count
= CVAL(buf
,0);
206 int ttl
= IVAL(buf
,1)/1000;
208 int osmajor
=CVAL(buf
,21);
209 int osminor
=CVAL(buf
,22);
210 uint32 servertype
= IVAL(buf
,23);
211 uint32 browse_type
= CVAL(buf
,27);
212 uint32 browse_sig
= CVAL(buf
,29);
213 char *comment
= buf
+31;
215 struct work_record
*work
;
217 char *serv_name
= dgram
->source_name
.name
;
222 DEBUG(4,("Announce(%d) %s(%x)",command
,name
,name
[15]));
223 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
224 namestr(&dgram
->dest_name
),update_count
,ttl
,osmajor
,osminor
,
225 servertype
,browse_type
,browse_sig
,comment
));
229 if (dgram
->dest_name
.name_type
== 0 && command
== ANN_HostAnnouncement
)
231 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
235 if (command
== ANN_DomainAnnouncement
&&
236 ((!strequal(dgram
->dest_name
.name
, MSBROWSE
)) ||
237 dgram
->dest_name
.name_type
!= 0x1))
239 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
240 command
, inet_ntoa(ip
), namestr(&dgram
->dest_name
)));
244 if (!strequal(dgram
->dest_name
.scope
,scope
)) return;
246 if (command
== ANN_DomainAnnouncement
) {
247 /* XXXX if we are a master browser for the workgroup work_name,
248 then there is a local subnet configuration problem. only
249 we should be sending out such domain announcements, because
250 as the master browser, that is our job.
252 stop being a master browser, and force an election. this will
253 sort out the network problem. hopefully.
259 work_name
= dgram
->dest_name
.name
;
262 /* we need some way of finding out about new workgroups
263 that appear to be sending packets to us. The name_type checks make
264 sure we don't add host names as workgroups */
265 if (command
== ANN_HostAnnouncement
&&
266 (dgram
->dest_name
.name_type
== 0x1d ||
267 dgram
->dest_name
.name_type
== 0x1e))
270 if (!(work
= find_workgroupstruct(d
, work_name
,add
)))
273 DEBUG(4, ("workgroup %s on %s\n", work
->work_group
, serv_name
));
277 /* add them to our browse list, and update the browse.dat file */
278 add_server_entry(d
,work
,name
,servertype
,ttl
,comment
,True
);
282 /* the tell become backup code is broken, no great harm is done by
284 tell_become_backup();
287 /* XXXX over-kill: i don't think we should really be doing this,
288 but it doesn't do much harm other than to add extra network
289 traffic. to be more precise, we should (possibly) only
290 sync browse lists with a host that sends an
291 ANN_LocalMasterAnnouncement or an ANN_DomainAnnouncement.
295 /* get their browse list from them and add it to ours. */
296 add_browser_entry(serv_name
,dgram
->dest_name
.name_type
,
297 work
->work_group
,30,ip
);
300 /*******************************************************************
301 process a master announcement frame
302 ******************************************************************/
303 static void process_master_announce(struct packet_struct
*p
,char *buf
)
305 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
306 struct in_addr ip
= dgram
->header
.source_ip
;
307 struct subnet_record
*d
= find_subnet(ip
);
308 struct subnet_record
*mydomain
= find_subnet(*iface_bcast(ip
));
310 struct work_record
*work
;
313 DEBUG(3,("Master Announce from %s (%s)\n",name
,inet_ntoa(ip
)));
315 if (same_context(dgram
)) return;
317 if (!d
|| !mydomain
) return;
319 if (!lp_domain_master()) return;
321 for (work
= mydomain
->workgrouplist
; work
; work
= work
->next
)
325 /* merge browse lists with them */
326 add_browser_entry(name
,0x1b, work
->work_group
,30,ip
);
331 /*******************************************************************
332 process a receive backup list request
334 we receive a list of servers, and we attempt to locate them all on
335 our local subnet, and sync browse lists with them on the workgroup
336 they are said to be in.
338 XXXX NOTE: this function is in overdrive. it should not really do
339 half of what it actually does (it should pick _one_ name from the
340 list received and sync with it at regular intervals, rather than
341 sync with them all only once!)
343 ******************************************************************/
344 static void process_rcv_backup_list(struct packet_struct
*p
,char *buf
)
346 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
347 struct in_addr ip
= dgram
->header
.source_ip
;
348 int count
= CVAL(buf
,0);
349 uint32 info
= IVAL(buf
,1); /* XXXX caller's incremental info */
352 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
353 namestr(&dgram
->dest_name
), inet_ntoa(ip
),
356 if (same_context(dgram
)) return;
358 if (count
<= 0) return;
360 /* go through the list of servers attempting to sync browse lists */
361 for (buf1
= buf
+5; *buf1
&& count
; buf1
= skip_string(buf1
, 1), --count
)
363 struct in_addr back_ip
;
364 struct subnet_record
*d
;
366 DEBUG(4,("Searching for backup browser %s at %s...\n",
367 buf1
, inet_ntoa(ip
)));
369 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
370 approach is to use reply_name_query functionality to find the name */
372 back_ip
= *interpret_addr2(buf1
);
374 if (zero_ip(back_ip
))
376 DEBUG(4,("Failed to find backup browser server using DNS\n"));
380 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip
)));
381 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
383 /* XXXX function needs work */
386 if ((d
= find_subnet(back_ip
)))
388 struct subnet_record
*d1
;
389 for (d1
= subnetlist
; d1
; d1
= d1
->next
)
391 struct work_record
*work
;
392 for (work
= d1
->workgrouplist
; work
; work
= work
->next
)
394 if (work
->token
== 0 /* token */)
396 queue_netbios_packet(d1
,ClientNMB
,NMB_QUERY
,NAME_QUERY_SRV_CHK
,
397 work
->work_group
,0x1d,0,0,
398 False
,False
,back_ip
,back_ip
);
408 /****************************************************************************
409 send a backup list response.
410 **************************************************************************/
411 static void send_backup_list(char *work_name
, struct nmb_name
*src_name
,
412 int token
, uint32 info
,
413 int name_type
, struct in_addr ip
)
415 struct subnet_record
*d
;
417 char *p
, *countptr
, *nameptr
;
419 char *theirname
= src_name
->name
;
421 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
422 work_name
, inet_ntoa(ip
),
423 myname
,0x0,theirname
,0x0));
425 if (name_type
== 0x1d)
427 DEBUG(4,("master browsers: "));
429 else if (name_type
== 0x1b)
431 DEBUG(4,("domain controllers: "));
435 DEBUG(0,("backup request for unknown type %0x\n", name_type
));
439 bzero(outbuf
,sizeof(outbuf
));
442 CVAL(p
,0) = ANN_GetBackupListResp
; /* backup list response */
447 SIVAL(p
,1,info
); /* the sender's unique info */
455 for (d
= subnetlist
; d
; d
= d
->next
)
457 struct work_record
*work
;
459 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
461 struct server_record
*s
;
463 if (!strequal(work
->work_group
, work_name
)) continue;
465 for (s
= work
->serverlist
; s
; s
= s
->next
)
470 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) continue;
472 for (n
= nameptr
; n
< p
; n
= skip_string(n
, 1))
474 if (strequal(n
, s
->serv
.name
)) found
= True
;
477 if (found
) continue; /* exclude names already added */
479 /* workgroup request: include all backup browsers in the list */
480 /* domain request: include all domain members in the list */
482 if ((name_type
== 0x1d && (s
->serv
.type
& MASTER_TYPE
)) ||
483 (name_type
== 0x1b && (s
->serv
.type
& DOMCTL_TYPE
)))
485 DEBUG(4, ("%s ", s
->serv
.name
));
488 strcpy(p
,s
->serv
.name
);
490 p
= skip_string(p
,1);
501 p
= skip_string(p
,1);
505 DEBUG(4, ("none\n"));
509 DEBUG(4, (" - count %d\n", count
));
512 CVAL(countptr
, 0) = count
;
515 int len
= PTR_DIFF(p
, outbuf
);
516 debug_browse_data(outbuf
, len
);
518 send_mailslot_reply(BROWSE_MAILSLOT
,ClientDGRAM
,outbuf
,PTR_DIFF(p
,outbuf
),
519 myname
,theirname
,0x0,0x0,ip
,*iface_ip(ip
));
523 /*******************************************************************
524 process a send backup list request
526 A client sends a backup list request to ask for a list of servers on
527 the net that maintain server lists for a domain. A server is then
528 chosen from this list to send NetServerEnum commands to to list
531 Currently samba only sends back one name in the backup list, its
532 own. For larger nets we'll have to add backups and send "become
533 backup" requests occasionally.
534 ******************************************************************/
535 static void process_send_backup_list(struct packet_struct
*p
,char *buf
)
537 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
538 struct in_addr ip
= dgram
->header
.source_ip
;
539 struct subnet_record
*d
;
540 struct work_record
*work
;
542 int token
= CVAL(buf
,0); /* sender's key index for the workgroup */
543 uint32 info
= IVAL(buf
,1); /* XXXX don't know: some sort of info */
544 int name_type
= dgram
->dest_name
.name_type
;
546 if (same_context(dgram
)) return;
548 if (name_type
!= 0x1b && name_type
!= 0x1d) {
549 DEBUG(0,("backup request to wrong type %d from %s\n",
550 name_type
,inet_ntoa(ip
)));
554 for (d
= subnetlist
; d
; d
= d
->next
)
556 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
558 if (strequal(work
->work_group
, dgram
->dest_name
.name
))
560 DEBUG(2,("sending backup list to %s %s id=%x\n",
561 namestr(&dgram
->dest_name
),inet_ntoa(ip
),info
));
563 send_backup_list(work
->work_group
,&dgram
->source_name
,
564 token
,info
,name_type
,ip
);
572 /*******************************************************************
573 process a reset browser state
576 0x1 - stop being a master browser and become a backup browser.
577 0x2 - discard browse lists, stop being a master browser, try again.
578 0x4 - stop being a master browser forever. no way. ain't gonna.
580 ******************************************************************/
581 static void process_reset_browser(struct packet_struct
*p
,char *buf
)
583 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
584 int state
= CVAL(buf
,0);
586 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
587 namestr(&dgram
->dest_name
), state
));
589 /* stop being a master but still deal with being a backup browser */
592 struct subnet_record
*d
;
593 for (d
= subnetlist
; d
; d
= d
->next
)
595 struct work_record
*work
;
596 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
600 become_nonmaster(d
,work
,SV_TYPE_DOMAIN_MASTER
|SV_TYPE_MASTER_BROWSER
);
606 /* XXXX documentation inconsistency: the above description does not
607 exactly tally with what is implemented for state & 0x2
610 /* totally delete all servers and start afresh */
613 struct subnet_record
*d
;
614 for (d
= subnetlist
; d
; d
= d
->next
)
616 struct work_record
*work
;
617 for (work
=d
->workgrouplist
;work
;work
=remove_workgroup(d
,work
,True
));
619 add_my_subnets(lp_workgroup());
622 /* stop browsing altogether. i don't think this is a good idea! */
625 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
629 /*******************************************************************
630 process a announcement request
632 clients send these when they want everyone to send an announcement
633 immediately. This can cause quite a storm of packets!
634 ******************************************************************/
635 static void process_announce_request(struct packet_struct
*p
,char *buf
)
637 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
638 struct work_record
*work
;
639 struct in_addr ip
= dgram
->header
.source_ip
;
640 struct subnet_record
*d
= find_subnet(ip
);
641 int token
= CVAL(buf
,0);
646 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
647 name
,namestr(&dgram
->dest_name
), token
));
649 if (strequal(dgram
->source_name
.name
,myname
)) return;
651 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
652 this workgroup before announcing, particularly as we only
653 respond on local interfaces anyway.
655 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
660 if (!d
->my_interface
) return;
662 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
664 /* XXXX BUG: the destination name type should also be checked,
665 not just the name. e.g if the name is WORKGROUP(0x1d) then
666 we should only respond if we own that name */
668 if (strequal(dgram
->dest_name
.name
,work
->work_group
))
670 work
->needannounce
= True
;
676 /****************************************************************************
677 depending on what announce has been made, we are only going to
678 accept certain types of name announce. XXXX untested code
680 check listening name type
681 ****************************************************************************/
682 BOOL
listening_type(struct packet_struct
*p
, int command
)
684 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
685 int type
= dgram
->dest_name
.name_type
;
689 case ANN_HostAnnouncement
:
691 if (type
!= 0x0 || type
!= 0x20) return (False
);
695 case ANN_AnnouncementRequest
:
707 case ANN_GetBackupListReq
:
713 case ANN_GetBackupListResp
:
719 case ANN_DomainAnnouncement
:
721 if (type
!= 0x1b || type
!= 0x1c) return (False
);
725 case ANN_MasterAnnouncement
:
727 if (type
!= 0x1d) return (False
);
731 case ANN_LocalMasterAnnouncement
:
733 if (type
!= 0x1c || type
!= 0x1d) return (False
);
737 return (True
); /* we're not dealing with unknown packet types */
741 /****************************************************************************
742 process a browse frame
743 ****************************************************************************/
744 void process_browse_packet(struct packet_struct
*p
,char *buf
,int len
)
746 int command
= CVAL(buf
,0);
749 case ANN_HostAnnouncement
:
750 case ANN_DomainAnnouncement
:
751 case ANN_LocalMasterAnnouncement
:
753 debug_browse_data(buf
, len
);
754 process_announce(p
,command
,buf
+1);
758 case ANN_AnnouncementRequest
:
760 process_announce_request(p
,buf
+1);
766 process_election(p
,buf
+1);
770 case ANN_GetBackupListReq
:
772 debug_browse_data(buf
, len
);
773 process_send_backup_list(p
,buf
+1);
777 case ANN_GetBackupListResp
:
779 debug_browse_data(buf
, len
);
780 process_rcv_backup_list(p
, buf
+1);
784 case ANN_ResetBrowserState
:
786 process_reset_browser(p
, buf
+1);
790 case ANN_MasterAnnouncement
:
792 process_master_announce(p
,buf
+1);
798 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
799 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
800 command
, namestr(&dgram
->source_name
),
801 inet_ntoa(p
->ip
), namestr(&dgram
->dest_name
)));