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
26 30 July 96: David.Chappell@mail.trincoll.edu
27 Expanded multiple workgroup domain master browser support.
34 extern int ClientDGRAM;
36 extern int DEBUGLEVEL;
38 extern BOOL CanRecurse;
41 extern int ClientDGRAM;
43 extern struct in_addr ipzero;
45 /* this is our domain/workgroup/server database */
46 extern struct subnet_record *subnetlist;
48 extern int updatecount;
50 extern time_t StartupTime;
52 extern BOOL updatedlists;
54 extern pstring myname;
57 /****************************************************************************
58 tell a server to become a backup browser
59 state - 0x01 become backup instead of master
60 - 0x02 remove all entries in browse list and become non-master
61 - 0x04 stop master browser service altogether. NT ignores this
62 **************************************************************************/
63 void reset_server(struct work_record *work, char *name, int state, struct in_addr ip)
68 bzero(outbuf,sizeof(outbuf));
71 CVAL(p,0) = ANN_ResetBrowserState;
75 DEBUG(2,("sending reset to %s %s of state %d\n",
76 name,inet_ntoa(ip),state));
78 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
79 conf_browsing_alias(work->token),name,0x20,0x1d,ip,*iface_ip(ip));
83 /****************************************************************************
84 tell a server to become a backup browser
85 **************************************************************************/
86 void tell_become_backup(void)
88 /* XXXX note: this function is currently unsuitable for use, as it
89 does not properly check that a server is in a fit state to become
90 a backup browser before asking it to be one.
93 struct subnet_record *d;
94 for (d = subnetlist; d; d = d->next)
96 struct work_record *work;
97 for (work = d->workgrouplist; work; work = work->next)
99 struct server_record *s;
103 for (s = work->serverlist; s; s = s->next)
105 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
109 if (strequal(conf_browsing_alias(work->token), s->serv.name)) continue;
111 if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
116 if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
118 if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
120 DEBUG(3,("num servers: %d num backups: %d\n",
121 num_servers, num_backups));
123 /* make first server a backup server. thereafter make every
124 tenth server a backup server */
125 if (num_backups != 0 && (num_servers+9) / num_backups > 10)
130 DEBUG(2,("sending become backup to %s %s for %s\n",
131 s->serv.name, inet_ntoa(d->bcast_ip),
134 /* type 11 request from conf_browsing_alias(work->token)(20) to WG(1e) for SERVER */
135 do_announce_request(s->serv.name, s->serv.name, work->work_group,
136 ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
143 /*******************************************************************
144 same context: scope. should check name_type as well, and makes sure
145 we don't process messages from ourselves
146 ******************************************************************/
147 BOOL same_context(struct dgram_packet *dgram)
149 if (!strequal(dgram->dest_name .scope,scope )) return True;
155 /*******************************************************************
156 am I listening on a name. XXXX check the type of name as well.
157 ******************************************************************/
158 BOOL listening_name(struct work_record *work, struct nmb_name *n)
160 if (strequal(n->name,conf_browsing_alias(work->token)) ||
161 strequal(n->name,work->work_group) ||
162 strequal(n->name,MSBROWSE))
171 /*******************************************************************
172 process a domain announcement frame
174 Announce frames come in 3 types. Servers send host announcements
175 (command=1) to let the master browswer know they are
176 available. Master browsers send local master announcements
177 (command=15) to let other masters and backups that they are the
178 master. They also send domain announcements (command=12) to register
181 The comment field of domain announcements contains the master
182 browser name. The servertype is used by NetServerEnum to select
183 resources. We just have to pass it to smbd (via browser.dat) and let
184 the client choose using bit masks.
185 ******************************************************************/
186 static void process_announce(struct packet_struct *p,uint16 command,char *buf)
188 struct dgram_packet *dgram = &p->packet.dgram;
189 struct in_addr ip = dgram->header.source_ip;
190 struct subnet_record *d = find_subnet(ip);
191 int update_count = CVAL(buf,0);
193 int ttl = IVAL(buf,1)/1000;
195 int osmajor=CVAL(buf,21);
196 int osminor=CVAL(buf,22);
197 uint32 servertype = IVAL(buf,23);
198 uint32 browse_type= CVAL(buf,27);
199 uint32 browse_sig = CVAL(buf,29);
200 char *comment = buf+31;
202 struct work_record *work;
204 char *serv_name = dgram->source_name.name;
209 DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
210 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
211 namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
212 servertype,browse_type,browse_sig,comment));
216 if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
218 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
222 if (command == ANN_DomainAnnouncement &&
223 ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
224 dgram->dest_name.name_type != 0x1))
226 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
227 command, inet_ntoa(ip), namestr(&dgram->dest_name)));
231 if (!strequal(dgram->dest_name.scope,scope )) return;
233 if (command == ANN_DomainAnnouncement) {
234 /* XXXX if we are a master browser for the workgroup work_name,
235 then there is a local subnet configuration problem. only
236 we should be sending out such domain announcements, because
237 as the master browser, that is our job.
239 stop being a master browser, and force an election. this will
240 sort out the network problem. hopefully.
246 work_name = dgram->dest_name.name;
249 /* we need some way of finding out about new workgroups
250 that appear to be sending packets to us. The name_type checks make
251 sure we don't add host names as workgroups */
252 if (command == ANN_HostAnnouncement &&
253 (dgram->dest_name.name_type == 0x1d ||
254 dgram->dest_name.name_type == 0x1e))
257 if (!(work = find_workgroupstruct(d, work_name,add)))
260 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
264 /* add them to our browse list, and update the browse.dat file */
265 add_server_entry(d,work,name,servertype,ttl,comment,True);
269 /* the tell become backup code is broken, no great harm is done by
271 tell_become_backup();
274 /* get the local_only browse list from the local master and add it
276 if (command == ANN_LocalMasterAnnouncement)
278 add_browser_entry(serv_name,dgram->dest_name.name_type,
279 work->work_group,30,ip,True);
283 /*******************************************************************
284 process a master announcement frame
285 ******************************************************************/
286 static void process_master_announce(struct packet_struct *p,char *buf)
288 struct dgram_packet *dgram = &p->packet.dgram;
289 struct in_addr ip = dgram->header.source_ip;
290 struct subnet_record *d = find_subnet(ip);
291 struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
292 char *to_name = dgram->dest_name.name; /* our primary name or an alias */
299 DEBUG(3,("Master Announce from %s (%s)\n", name, inet_ntoa(ip)));
301 if (same_context(dgram)) return;
303 if (!d || !mydomain) return;
305 token = conf_alias_to_token(to_name);
309 DEBUG(4, ("alias %s not known\n", to_name));
313 /* carry on only if we are a domain master under the server alias */
314 if (!conf_should_domain_master(token)) return;
316 /* Convert the server name by which the master browser
317 called this server to the workgroup name. */
318 if ((work_name = conf_workgroup_name(token)) == (char*)NULL)
320 DEBUG(4, ("process_master_announce(): no alias for \"%s\"\n", to_name));
324 /* merge browse lists with them */
325 add_browser_entry(name, 0x1b, work_name,30,ip,True);
328 /*******************************************************************
329 process a receive backup list request
331 we receive a list of servers, and we attempt to locate them all on
332 our local subnet, and sync browse lists with them on the workgroup
333 they are said to be in.
335 XXXX NOTE: this function is in overdrive. it should not really do
336 half of what it actually does (it should pick _one_ name from the
337 list received and sync with it at regular intervals, rather than
338 sync with them all only once!)
340 ******************************************************************/
341 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
343 struct dgram_packet *dgram = &p->packet.dgram;
344 struct in_addr ip = dgram->header.source_ip;
345 int count = CVAL(buf,0);
347 uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
350 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
351 namestr(&dgram->dest_name), inet_ntoa(ip),
354 if (same_context(dgram)) return;
356 if (count <= 0) return;
358 pick = sys_random(count);
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 subnet_record *d;
365 if (count != pick) continue;
367 DEBUG(4,("Searching for backup browser %s...\n", buf1));
369 if ((d = find_subnet(ip)) != NULL)
371 struct work_record *work;
372 for (work = d->workgrouplist; work; work = work->next)
374 if (work->token == 0 /* token */)
376 queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
377 work->token,work->work_group,0x1d,
379 False,False,ipzero,ipzero);
388 /****************************************************************************
389 send a backup list response.
390 **************************************************************************/
391 static void send_backup_list(struct work_record *work, struct nmb_name *src_name,
392 int token, uint32 info,
393 int name_type, struct in_addr ip)
396 char *p, *countptr, *nameptr;
398 char *theirname = src_name->name;
400 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
401 work->work_group, inet_ntoa(ip),
402 conf_browsing_alias(work->token),0x0,theirname,0x0));
404 if (name_type == 0x1d)
406 DEBUG(4,("master browsers: "));
408 else if (name_type == 0x1b)
410 DEBUG(4,("domain controllers: "));
414 DEBUG(0,("backup request for unknown type %0x\n", name_type));
418 bzero(outbuf,sizeof(outbuf));
421 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
426 SIVAL(p,1,info); /* the sender's unique info */
434 struct server_record *s;
436 for (s = work->serverlist; s; s = s->next)
441 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
443 for (n = nameptr; n < p; n = skip_string(n, 1))
445 if (strequal(n, s->serv.name)) found = True;
448 if (found) continue; /* exclude names already added */
450 /* workgroup request: include all backup browsers in the list */
451 /* domain request: include all domain members in the list */
453 if ((name_type == 0x1d && (s->serv.type & SV_TYPE_MASTER_BROWSER)) ||
454 (name_type == 0x1b && (s->serv.type & SV_TYPE_DOMAIN_BROWSER)))
456 DEBUG(4, ("%s ", s->serv.name));
459 strcpy(p,s->serv.name);
461 p = skip_string(p,1);
467 strcpy(p,conf_browsing_alias(work->token));
469 p = skip_string(p,1);
473 DEBUG(4, ("none\n"));
477 DEBUG(4, (" - count %d\n", count));
480 CVAL(countptr, 0) = count;
483 int len = PTR_DIFF(p, outbuf);
484 debug_browse_data(outbuf, len);
486 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
487 conf_browsing_alias(work->token),theirname,0x0,0x0,ip,*iface_ip(ip));
491 /*******************************************************************
492 process a send backup list request
494 A client sends a backup list request to ask for a list of servers on
495 the net that maintain server lists for a domain. A server is then
496 chosen from this list to send NetServerEnum commands to to list
499 Currently samba only sends back one name in the backup list, its
500 own. For larger nets we'll have to add backups and send "become
501 backup" requests occasionally.
502 ******************************************************************/
503 static void process_send_backup_list(struct packet_struct *p,char *buf)
505 struct dgram_packet *dgram = &p->packet.dgram;
506 struct in_addr ip = dgram->header.source_ip;
507 struct subnet_record *d;
508 struct work_record *work;
510 int token = CVAL(buf,0); /* sender's key index for the workgroup */
511 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
512 int name_type = dgram->dest_name.name_type;
514 if (same_context(dgram)) return;
516 if (name_type != 0x1b && name_type != 0x1d) {
517 DEBUG(0,("backup request to wrong type %d from %s\n",
518 name_type,inet_ntoa(ip)));
522 for (d = subnetlist; d; d = d->next)
524 for (work = d->workgrouplist; work; work = work->next)
526 if (strequal(work->work_group, dgram->dest_name.name))
528 DEBUG(2,("sending backup list to %s %s id=%x\n",
529 namestr(&dgram->dest_name),inet_ntoa(ip),info));
531 send_backup_list(work,&dgram->source_name,
532 token,info,name_type,ip);
540 /*******************************************************************
541 process a reset browser state
544 0x1 - stop being a master browser and become a backup browser.
545 0x2 - discard browse lists, stop being a master browser, try again.
546 0x4 - stop being a master browser forever. no way. ain't gonna.
548 ******************************************************************/
549 static void process_reset_browser(struct packet_struct *p,char *buf)
551 struct dgram_packet *dgram = &p->packet.dgram;
552 int state = CVAL(buf,0);
554 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
555 namestr(&dgram->dest_name), state));
557 /* stop being a master but still deal with being a backup browser */
560 struct subnet_record *d;
561 for (d = subnetlist; d; d = d->next)
563 struct work_record *work;
564 for (work = d->workgrouplist; work; work = work->next)
568 become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
574 /* XXXX documentation inconsistency: the above description does not
575 exactly tally with what is implemented for state & 0x2
578 /* totally delete all servers and start afresh */
581 /* remove all workgroups (and their servers) from database */
582 struct subnet_record *d;
583 for (d = subnetlist; d; d = d->next)
585 struct work_record *work;
586 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
589 /* add all known workgroups back into database */
590 add_workgroups_to_subnets();
593 /* stop browsing altogether. i don't think this is a good idea! */
596 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
600 /*******************************************************************
601 process a announcement request
603 clients send these when they want everyone to send an announcement
604 immediately. This can cause quite a storm of packets!
605 ******************************************************************/
606 static void process_announce_request(struct packet_struct *p,char *buf)
608 struct dgram_packet *dgram = &p->packet.dgram;
609 struct work_record *work;
610 struct in_addr ip = dgram->header.source_ip;
611 struct subnet_record *d = find_subnet(ip);
612 int token = CVAL(buf,0);
619 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
620 name,namestr(&dgram->dest_name), token));
622 /* look up the index for this workgroup */
623 wg_token = conf_workgroup_name_to_token(dgram->dest_name.name,myname);
624 if (wg_token == -1) return;
626 /* check that samba is participating in this workgroup */
627 if (!conf_should_workgroup_member(wg_token)) return;
629 /* find samba's NetBIOS alias it operates under in this workgroup */
630 if ((samba_alias = conf_browsing_alias(wg_token)) == (char*)NULL) return;
632 /* ignore announce requests from samba under its own alias.
633 this should no longer happen because code has been added to
634 discard packets from ourself. */
635 if (strequal(dgram->source_name.name,samba_alias)) return;
639 /* XXXX BUG: the destination name type should also be checked,
640 not just the name. e.g if the name is WORKGROUP(0x1d) then
641 we should only respond if we own that name */
643 for (work = d->workgrouplist; work; work = work->next)
645 if (wg_token == work->token) work->needannounce = True;
650 /****************************************************************************
651 process a browse frame
652 ****************************************************************************/
653 void process_browse_packet(struct packet_struct *p,char *buf,int len)
655 int command = CVAL(buf,0);
658 case ANN_HostAnnouncement:
659 case ANN_DomainAnnouncement:
660 case ANN_LocalMasterAnnouncement:
662 debug_browse_data(buf, len);
663 process_announce(p,command,buf+1);
667 case ANN_AnnouncementRequest:
669 process_announce_request(p,buf+1);
675 process_election(p,buf+1);
679 case ANN_GetBackupListReq:
681 debug_browse_data(buf, len);
682 process_send_backup_list(p,buf+1);
686 case ANN_GetBackupListResp:
688 debug_browse_data(buf, len);
689 process_rcv_backup_list(p, buf+1);
693 case ANN_ResetBrowserState:
695 process_reset_browser(p, buf+1);
699 case ANN_MasterAnnouncement:
701 process_master_announce(p,buf+1);
707 struct dgram_packet *dgram = &p->packet.dgram;
708 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
709 command, namestr(&dgram->source_name),
710 inet_ntoa(p->ip), namestr(&dgram->dest_name)));