2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1997
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(False
,BROWSE_MAILSLOT
,ClientDGRAM
,
83 outbuf
,PTR_DIFF(p
,outbuf
),
84 myname
,name
,0x20,0x1d,ip
,*iface_ip(ip
));
88 /****************************************************************************
89 tell a server to become a backup browser
90 **************************************************************************/
91 void tell_become_backup(void)
93 /* XXXX note: this function is currently unsuitable for use, as it
94 does not properly check that a server is in a fit state to become
95 a backup browser before asking it to be one.
98 struct subnet_record
*d
;
99 for (d
= FIRST_SUBNET
; d
; d
= NEXT_SUBNET_EXCLUDING_WINS(d
))
101 struct work_record
*work
;
102 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
104 struct server_record
*s
;
108 for (s
= work
->serverlist
; s
; s
= s
->next
)
110 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) continue;
114 if (strequal(myname
, s
->serv
.name
)) continue;
116 if (s
->serv
.type
& SV_TYPE_BACKUP_BROWSER
) {
121 if (s
->serv
.type
& SV_TYPE_MASTER_BROWSER
) continue;
123 if (!(s
->serv
.type
& SV_TYPE_POTENTIAL_BROWSER
)) continue;
125 DEBUG(3,("num servers: %d num backups: %d\n",
126 num_servers
, num_backups
));
128 /* make first server a backup server. thereafter make every
129 tenth server a backup server */
130 if (num_backups
!= 0 && (num_servers
+9) / num_backups
> 10)
135 DEBUG(2,("sending become backup to %s %s for %s\n",
136 s
->serv
.name
, inet_ntoa(d
->bcast_ip
),
139 /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
140 do_announce_request(s
->serv
.name
, work
->work_group
,
141 ANN_BecomeBackup
, 0x20, 0x1e, d
->bcast_ip
);
148 /*******************************************************************
149 same context: scope. should check name_type as well, and makes sure
150 we don't process messages from ourselves
151 ******************************************************************/
152 BOOL
same_context(struct dgram_packet
*dgram
)
154 if (!strequal(dgram
->dest_name
.scope
,scope
)) return(True
);
155 if ( strequal(dgram
->source_name
.name
,myname
)) return(True
);
161 /*******************************************************************
162 process a domain announcement frame
164 Announce frames come in 3 types. Servers send host announcements
165 (command=1) to let the master browswer know they are
166 available. Master browsers send local master announcements
167 (command=15) to let other masters and backups that they are the
168 master. They also send domain announcements (command=12) to register
171 The comment field of domain announcements contains the master
172 browser name. The servertype is used by NetServerEnum to select
173 resources. We just have to pass it to smbd (via browser.dat) and let
174 the client choose using bit masks.
175 ******************************************************************/
176 static void process_localnet_announce(struct packet_struct
*p
,uint16 command
,char *buf
)
178 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
179 struct subnet_record
*d
= find_subnet(p
->ip
); /* Explicitly exclude WINS - local nets only */
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(p
->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 DEBUG(4,("search for workgroup: %s (add? %s)\n",
247 work_name
, BOOLSTR(add
)));
249 if (!(work
= find_workgroupstruct(d
, work_name
,add
)))
252 DEBUG(4, ("workgroup %s on %s\n", work
->work_group
, serv_name
));
256 /* add them to our browse list, and update the browse.dat file */
257 add_server_entry(d
,work
,name
,servertype
,ttl
,comment
,True
);
261 /* the tell become backup code is broken, no great harm is done by
263 tell_become_backup();
266 #if 0 /* JRA TEST - I Think this code should not be here */
267 /* get the local_only browse list from the local master and add it
269 if (command
== ANN_LocalMasterAnnouncement
)
271 add_browser_entry(serv_name
,dgram
->dest_name
.name_type
,
272 work
->work_group
,30,p
->ip
,True
);
274 #endif /* END JRA TEST */
277 /*******************************************************************
278 process a master announcement frame
279 Domain master browsers recieve these from local masters. The Domain
280 master should then issue a sync with the local master, asking for
281 that machines local server list.
282 ******************************************************************/
283 static void process_master_announce(struct packet_struct
*p
,char *buf
)
285 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
287 struct work_record
*work
;
290 DEBUG(3,("process_master_announce: Master Announce from %s (%s)\n",name
,inet_ntoa(p
->ip
)));
292 if (same_context(dgram
)) return;
296 DEBUG(3,("process_master_announce: No wins subnet !\n"));
300 if (!lp_domain_master())
302 DEBUG(3,("process_master_announce: Not configured as domain master - ignoring master announce.\n"));
306 for (work
= wins_subnet
->workgrouplist
; work
; work
= work
->next
)
308 if (AM_MASTER(work
) || AM_DOMMST(work
))
310 /* merge browse lists with them */
311 add_browser_entry(name
,0x1d, work
->work_group
,30,wins_subnet
,p
->ip
,True
);
316 /*******************************************************************
317 process a receive backup list request
319 we receive a list of servers, and we attempt to locate them all on
320 our local subnet, and sync browse lists with them on the workgroup
321 they are said to be in.
323 XXXX NOTE: this function is in overdrive. it should not really do
324 half of what it actually does (it should pick _one_ name from the
325 list received and sync with it at regular intervals, rather than
326 sync with them all only once!)
328 ******************************************************************/
329 static void process_rcv_backup_list(struct packet_struct
*p
,char *buf
)
331 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
332 int count
= CVAL(buf
,0);
333 uint32 info
= IVAL(buf
,1); /* XXXX caller's incremental info */
336 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
337 namestr(&dgram
->dest_name
), inet_ntoa(p
->ip
),
340 if (same_context(dgram
)) return;
342 if (count
<= 0) return;
344 /* go through the list of servers attempting to sync browse lists */
345 for (buf1
= buf
+5; *buf1
&& count
; buf1
= skip_string(buf1
, 1), --count
)
347 struct in_addr back_ip
;
348 /* struct subnet_record *d; */
350 DEBUG(4,("Searching for backup browser %s at %s...\n",
351 buf1
, inet_ntoa(p
->ip
)));
353 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
354 approach is to use reply_name_query functionality to find the name */
356 back_ip
= *interpret_addr2(buf1
);
358 if (zero_ip(back_ip
))
360 DEBUG(4,("Failed to find backup browser server using DNS\n"));
364 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip
)));
365 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
368 /* XXXX function needs work */
371 if ((d
= find_subnet(back_ip
)))
373 struct subnet_record
*d1
;
374 for (d1
= subnetlist
; d1
; d1
= d1
->next
)
376 struct work_record
*work
;
377 for (work
= d1
->workgrouplist
; work
; work
= work
->next
)
379 if (work
->token
== 0 /* token */)
381 queue_netbios_packet(d1
,ClientNMB
,NMB_QUERY
,NAME_QUERY_SRV_CHK
,
382 work
->work_group
,0x1d,
384 False
,False
,back_ip
,back_ip
);
395 /****************************************************************************
396 send a backup list response.
397 **************************************************************************/
398 static void send_backup_list(char *work_name
, struct nmb_name
*src_name
,
399 int token
, uint32 info
,
400 int name_type
, struct in_addr ip
)
403 char *p
, *countptr
, *nameptr
;
405 char *theirname
= src_name
->name
;
407 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
408 work_name
, inet_ntoa(ip
),
409 myname
,0x0,theirname
,0x0));
411 if (name_type
== 0x1d)
413 DEBUG(4,("master browsers: "));
415 else if (name_type
== 0x1b)
417 DEBUG(4,("domain controllers: "));
421 DEBUG(0,("backup request for unknown type %0x\n", name_type
));
425 bzero(outbuf
,sizeof(outbuf
));
428 CVAL(p
,0) = ANN_GetBackupListResp
; /* backup list response */
433 SIVAL(p
,1,info
); /* the sender's unique info */
441 for (d
= FIRST_SUBNET
; d
; d
= NEXT_SUBNET_INCLUDING_WINS(d
))
443 struct work_record
*work
;
445 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
447 struct server_record
*s
;
449 if (!strequal(work
->work_group
, work_name
)) continue;
451 for (s
= work
->serverlist
; s
; s
= s
->next
)
456 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) continue;
458 for (n
= nameptr
; n
< p
; n
= skip_string(n
, 1))
460 if (strequal(n
, s
->serv
.name
)) found
= True
;
463 if (found
) continue; /* exclude names already added */
465 /* workgroup request: include all backup browsers in the list */
466 /* domain request: include all domain members in the list */
468 if ((name_type
== 0x1d && (s
->serv
.type
& MASTER_TYPE
)) ||
469 (name_type
== 0x1b && (s
->serv
.type
& DOMCTL_TYPE
)))
471 DEBUG(4, ("%s ", s
->serv
.name
));
474 strcpy(p
,s
->serv
.name
);
476 p
= skip_string(p
,1);
487 p
= skip_string(p
,1);
491 DEBUG(4, ("none\n"));
495 DEBUG(4, (" - count %d\n", count
));
498 CVAL(countptr
, 0) = count
;
501 int len
= PTR_DIFF(p
, outbuf
);
502 debug_browse_data(outbuf
, len
);
504 send_mailslot_reply(False
,BROWSE_MAILSLOT
,ClientDGRAM
,
505 outbuf
,PTR_DIFF(p
,outbuf
),
506 myname
,theirname
,0x0,0x0,ip
,*iface_ip(ip
));
510 /*******************************************************************
511 process a send backup list request
513 A client sends a backup list request to ask for a list of servers on
514 the net that maintain server lists for a domain. A server is then
515 chosen from this list to send NetServerEnum commands to to list
518 Currently samba only sends back one name in the backup list, its
519 own. For larger nets we'll have to add backups and send "become
520 backup" requests occasionally.
521 ******************************************************************/
522 static void process_send_backup_list(struct packet_struct
*p
,char *buf
)
524 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
525 struct in_addr ip
= dgram
->header
.source_ip
;
526 struct subnet_record
*d
;
527 struct work_record
*work
;
529 int token
= CVAL(buf
,0); /* sender's key index for the workgroup */
530 uint32 info
= IVAL(buf
,1); /* XXXX don't know: some sort of info */
531 int name_type
= dgram
->dest_name
.name_type
;
533 if (same_context(dgram
)) return;
535 if (name_type
!= 0x1b && name_type
!= 0x1d) {
536 DEBUG(0,("backup request to wrong type %d from %s\n",
537 name_type
,inet_ntoa(ip
)));
541 for (d
= subnetlist
; d
; d
= d
->next
)
543 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
545 if (strequal(work
->work_group
, dgram
->dest_name
.name
))
547 DEBUG(2,("sending backup list to %s %s id=%x\n",
548 namestr(&dgram
->dest_name
),inet_ntoa(ip
),info
));
550 send_backup_list(work
->work_group
,&dgram
->source_name
,
551 token
,info
,name_type
,ip
);
559 /*******************************************************************
560 process a reset browser state
563 0x1 - stop being a master browser and become a backup browser.
564 0x2 - discard browse lists, stop being a master browser, try again.
565 0x4 - stop being a master browser forever. no way. ain't gonna.
567 ******************************************************************/
568 static void process_reset_browser(struct packet_struct
*p
,char *buf
)
570 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
571 int state
= CVAL(buf
,0);
573 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
574 namestr(&dgram
->dest_name
), state
));
576 /* stop being a master but still deal with being a backup browser */
579 struct subnet_record
*d
;
580 for (d
= FIRST_SUBNET
; d
; d
= NEXT_SUBNET_EXCLUDING_WINS(d
))
582 struct work_record
*work
;
583 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
587 unbecome_local_master(d
,work
,SV_TYPE_MASTER_BROWSER
);
593 /* XXXX documentation inconsistency: the above description does not
594 exactly tally with what is implemented for state & 0x2
597 /* totally delete all servers and start afresh */
600 struct subnet_record
*d
;
601 for (d
= FIRST_SUBNET
; d
; d
= NEXT_SUBNET_INCLUDING_WINS(d
))
603 struct work_record
*work
;
604 for (work
=d
->workgrouplist
;work
;work
=remove_workgroup(d
,work
,True
));
606 add_my_subnets(lp_workgroup());
609 /* stop browsing altogether. i don't think this is a good idea! */
612 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
616 /*******************************************************************
617 process a announcement request
619 clients send these when they want everyone to send an announcement
620 immediately. This can cause quite a storm of packets!
621 ******************************************************************/
622 static void process_announce_request(struct packet_struct
*p
,char *buf
)
624 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
625 struct work_record
*work
;
626 struct in_addr ip
= dgram
->header
.source_ip
;
627 struct subnet_record
*d
= find_subnet(ip
); /* Explicitly NO WINS */
628 int token
= CVAL(buf
,0);
633 DEBUG(3,("process_announce_request: Announce request from %s to %s token=0x%X\n",
634 name
,namestr(&dgram
->dest_name
), token
));
636 if (strequal(dgram
->source_name
.name
,myname
)) return;
638 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
639 this workgroup before announcing, particularly as we only
640 respond on local interfaces anyway.
642 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
647 DEBUG(3,("process_announce_request: No local interface to announce to %s\n",
652 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
654 /* XXXX BUG: the destination name type should also be checked,
655 not just the name. e.g if the name is WORKGROUP(0x1d) then
656 we should only respond if we own that name */
658 if (strequal(dgram
->dest_name
.name
,work
->work_group
))
660 work
->needannounce
= True
;
667 /****************************************************************************
668 process a browse frame
669 ****************************************************************************/
670 void process_browse_packet(struct packet_struct
*p
,char *buf
,int len
)
672 int command
= CVAL(buf
,0);
675 case ANN_HostAnnouncement
:
676 case ANN_DomainAnnouncement
:
677 case ANN_LocalMasterAnnouncement
:
679 debug_browse_data(buf
, len
);
680 process_localnet_announce(p
,command
,buf
+1);
684 case ANN_AnnouncementRequest
:
686 process_announce_request(p
,buf
+1);
692 process_election(p
,buf
+1);
696 case ANN_GetBackupListReq
:
698 debug_browse_data(buf
, len
);
699 process_send_backup_list(p
,buf
+1);
703 case ANN_GetBackupListResp
:
705 debug_browse_data(buf
, len
);
706 process_rcv_backup_list(p
, buf
+1);
710 case ANN_ResetBrowserState
:
712 process_reset_browser(p
, buf
+1);
716 case ANN_MasterAnnouncement
:
718 process_master_announce(p
,buf
+1);
724 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
725 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
726 command
, namestr(&dgram
->source_name
),
727 inet_ntoa(p
->ip
), namestr(&dgram
->dest_name
)));