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 process a domain announcement frame
171 Announce frames come in 3 types. Servers send host announcements
172 (command=1) to let the master browswer know they are
173 available. Master browsers send local master announcements
174 (command=15) to let other masters and backups that they are the
175 master. They also send domain announcements (command=12) to register
178 The comment field of domain announcements contains the master
179 browser name. The servertype is used by NetServerEnum to select
180 resources. We just have to pass it to smbd (via browser.dat) and let
181 the client choose using bit masks.
182 ******************************************************************/
183 static void process_announce(struct packet_struct *p,uint16 command,char *buf)
185 struct dgram_packet *dgram = &p->packet.dgram;
186 struct in_addr ip = dgram->header.source_ip;
187 struct subnet_record *d = find_subnet(ip);
188 int update_count = CVAL(buf,0);
190 int ttl = IVAL(buf,1)/1000;
192 int osmajor=CVAL(buf,21);
193 int osminor=CVAL(buf,22);
194 uint32 servertype = IVAL(buf,23);
195 uint32 browse_type= CVAL(buf,27);
196 uint32 browse_sig = CVAL(buf,29);
197 char *comment = buf+31;
199 struct work_record *work;
201 char *serv_name = dgram->source_name.name;
206 DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
207 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
208 namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
209 servertype,browse_type,browse_sig,comment));
213 if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
215 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
219 if (command == ANN_DomainAnnouncement &&
220 ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
221 dgram->dest_name.name_type != 0x1))
223 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
224 command, inet_ntoa(ip), namestr(&dgram->dest_name)));
228 if (!strequal(dgram->dest_name.scope,scope )) return;
230 if (command == ANN_DomainAnnouncement) {
231 /* XXXX if we are a master browser for the workgroup work_name,
232 then there is a local subnet configuration problem. only
233 we should be sending out such domain announcements, because
234 as the master browser, that is our job.
236 stop being a master browser, and force an election. this will
237 sort out the network problem. hopefully.
243 work_name = dgram->dest_name.name;
246 /* we need some way of finding out about new workgroups
247 that appear to be sending packets to us. The name_type checks make
248 sure we don't add host names as workgroups */
249 if (command == ANN_HostAnnouncement &&
250 (dgram->dest_name.name_type == 0x1d ||
251 dgram->dest_name.name_type == 0x1e))
254 if (!(work = find_workgroupstruct(d, work_name,add)))
257 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
261 /* add them to our browse list, and update the browse.dat file */
262 add_server_entry(d,work,name,servertype,ttl,comment,True);
266 /* the tell become backup code is broken, no great harm is done by
268 tell_become_backup();
271 /* get the local_only browse list from the local master and add it
273 if (command == ANN_LocalMasterAnnouncement)
275 add_browser_entry(serv_name,dgram->dest_name.name_type,
276 work->work_group,30,ip,True);
280 /*******************************************************************
281 process a master announcement frame
282 ******************************************************************/
283 static void process_master_announce(struct packet_struct *p,char *buf)
285 struct dgram_packet *dgram = &p->packet.dgram;
286 struct in_addr ip = dgram->header.source_ip;
287 struct subnet_record *d = find_subnet(ip);
288 struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
290 struct work_record *work;
293 DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip)));
295 if (same_context(dgram)) return;
297 if (!d || !mydomain) return;
299 if (!lp_domain_master()) return;
301 for (work = mydomain->workgrouplist; work; work = work->next)
305 /* merge browse lists with them */
306 add_browser_entry(name,0x1b, work->work_group,30,ip,True);
311 /*******************************************************************
312 process a receive backup list request
314 we receive a list of servers, and we attempt to locate them all on
315 our local subnet, and sync browse lists with them on the workgroup
316 they are said to be in.
318 XXXX NOTE: this function is in overdrive. it should not really do
319 half of what it actually does (it should pick _one_ name from the
320 list received and sync with it at regular intervals, rather than
321 sync with them all only once!)
323 ******************************************************************/
324 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
326 struct dgram_packet *dgram = &p->packet.dgram;
327 struct in_addr ip = dgram->header.source_ip;
328 int count = CVAL(buf,0);
329 uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
332 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
333 namestr(&dgram->dest_name), inet_ntoa(ip),
336 if (same_context(dgram)) return;
338 if (count <= 0) return;
340 /* go through the list of servers attempting to sync browse lists */
341 for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
343 struct in_addr back_ip;
344 struct subnet_record *d;
346 DEBUG(4,("Searching for backup browser %s at %s...\n",
347 buf1, inet_ntoa(ip)));
349 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
350 approach is to use reply_name_query functionality to find the name */
352 back_ip = *interpret_addr2(buf1);
354 if (zero_ip(back_ip))
356 DEBUG(4,("Failed to find backup browser server using DNS\n"));
360 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
361 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
363 /* XXXX function needs work */
366 if ((d = find_subnet(back_ip)))
368 struct subnet_record *d1;
369 for (d1 = subnetlist; d1; d1 = d1->next)
371 struct work_record *work;
372 for (work = d1->workgrouplist; work; work = work->next)
374 if (work->token == 0 /* token */)
376 queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
377 work->work_group,0x1d,
379 False,False,back_ip,back_ip);
389 /****************************************************************************
390 send a backup list response.
391 **************************************************************************/
392 static void send_backup_list(char *work_name, struct nmb_name *src_name,
393 int token, uint32 info,
394 int name_type, struct in_addr ip)
397 char *p, *countptr, *nameptr;
399 char *theirname = src_name->name;
401 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
402 work_name, inet_ntoa(ip),
403 myname,0x0,theirname,0x0));
405 if (name_type == 0x1d)
407 DEBUG(4,("master browsers: "));
409 else if (name_type == 0x1b)
411 DEBUG(4,("domain controllers: "));
415 DEBUG(0,("backup request for unknown type %0x\n", name_type));
419 bzero(outbuf,sizeof(outbuf));
422 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
427 SIVAL(p,1,info); /* the sender's unique info */
435 for (d = subnetlist; d; d = d->next)
437 struct work_record *work;
439 for (work = d->workgrouplist; work; work = work->next)
441 struct server_record *s;
443 if (!strequal(work->work_group, work_name)) continue;
445 for (s = work->serverlist; s; s = s->next)
450 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
452 for (n = nameptr; n < p; n = skip_string(n, 1))
454 if (strequal(n, s->serv.name)) found = True;
457 if (found) continue; /* exclude names already added */
459 /* workgroup request: include all backup browsers in the list */
460 /* domain request: include all domain members in the list */
462 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
463 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
465 DEBUG(4, ("%s ", s->serv.name));
468 strcpy(p,s->serv.name);
470 p = skip_string(p,1);
481 p = skip_string(p,1);
485 DEBUG(4, ("none\n"));
489 DEBUG(4, (" - count %d\n", count));
492 CVAL(countptr, 0) = count;
495 int len = PTR_DIFF(p, outbuf);
496 debug_browse_data(outbuf, len);
498 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
499 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
503 /*******************************************************************
504 process a send backup list request
506 A client sends a backup list request to ask for a list of servers on
507 the net that maintain server lists for a domain. A server is then
508 chosen from this list to send NetServerEnum commands to to list
511 Currently samba only sends back one name in the backup list, its
512 own. For larger nets we'll have to add backups and send "become
513 backup" requests occasionally.
514 ******************************************************************/
515 static void process_send_backup_list(struct packet_struct *p,char *buf)
517 struct dgram_packet *dgram = &p->packet.dgram;
518 struct in_addr ip = dgram->header.source_ip;
519 struct subnet_record *d;
520 struct work_record *work;
522 int token = CVAL(buf,0); /* sender's key index for the workgroup */
523 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
524 int name_type = dgram->dest_name.name_type;
526 if (same_context(dgram)) return;
528 if (name_type != 0x1b && name_type != 0x1d) {
529 DEBUG(0,("backup request to wrong type %d from %s\n",
530 name_type,inet_ntoa(ip)));
534 for (d = subnetlist; d; d = d->next)
536 for (work = d->workgrouplist; work; work = work->next)
538 if (strequal(work->work_group, dgram->dest_name.name))
540 DEBUG(2,("sending backup list to %s %s id=%x\n",
541 namestr(&dgram->dest_name),inet_ntoa(ip),info));
543 send_backup_list(work->work_group,&dgram->source_name,
544 token,info,name_type,ip);
552 /*******************************************************************
553 process a reset browser state
556 0x1 - stop being a master browser and become a backup browser.
557 0x2 - discard browse lists, stop being a master browser, try again.
558 0x4 - stop being a master browser forever. no way. ain't gonna.
560 ******************************************************************/
561 static void process_reset_browser(struct packet_struct *p,char *buf)
563 struct dgram_packet *dgram = &p->packet.dgram;
564 int state = CVAL(buf,0);
566 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
567 namestr(&dgram->dest_name), state));
569 /* stop being a master but still deal with being a backup browser */
572 struct subnet_record *d;
573 for (d = subnetlist; d; d = d->next)
575 struct work_record *work;
576 for (work = d->workgrouplist; work; work = work->next)
580 become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
586 /* XXXX documentation inconsistency: the above description does not
587 exactly tally with what is implemented for state & 0x2
590 /* totally delete all servers and start afresh */
593 struct subnet_record *d;
594 for (d = subnetlist; d; d = d->next)
596 struct work_record *work;
597 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
599 add_my_subnets(lp_workgroup());
602 /* stop browsing altogether. i don't think this is a good idea! */
605 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
609 /*******************************************************************
610 process a announcement request
612 clients send these when they want everyone to send an announcement
613 immediately. This can cause quite a storm of packets!
614 ******************************************************************/
615 static void process_announce_request(struct packet_struct *p,char *buf)
617 struct dgram_packet *dgram = &p->packet.dgram;
618 struct work_record *work;
619 struct in_addr ip = dgram->header.source_ip;
620 struct subnet_record *d = find_subnet(ip);
621 int token = CVAL(buf,0);
626 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
627 name,namestr(&dgram->dest_name), token));
629 if (strequal(dgram->source_name.name,myname)) return;
631 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
632 this workgroup before announcing, particularly as we only
633 respond on local interfaces anyway.
635 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
640 for (work = d->workgrouplist; work; work = work->next)
642 /* XXXX BUG: the destination name type should also be checked,
643 not just the name. e.g if the name is WORKGROUP(0x1d) then
644 we should only respond if we own that name */
646 if (strequal(dgram->dest_name.name,work->work_group))
648 work->needannounce = True;
655 /****************************************************************************
656 process a browse frame
657 ****************************************************************************/
658 void process_browse_packet(struct packet_struct *p,char *buf,int len)
660 int command = CVAL(buf,0);
663 case ANN_HostAnnouncement:
664 case ANN_DomainAnnouncement:
665 case ANN_LocalMasterAnnouncement:
667 debug_browse_data(buf, len);
668 process_announce(p,command,buf+1);
672 case ANN_AnnouncementRequest:
674 process_announce_request(p,buf+1);
680 process_election(p,buf+1);
684 case ANN_GetBackupListReq:
686 debug_browse_data(buf, len);
687 process_send_backup_list(p,buf+1);
691 case ANN_GetBackupListResp:
693 debug_browse_data(buf, len);
694 process_rcv_backup_list(p, buf+1);
698 case ANN_ResetBrowserState:
700 process_reset_browser(p, buf+1);
704 case ANN_MasterAnnouncement:
706 process_master_announce(p,buf+1);
712 struct dgram_packet *dgram = &p->packet.dgram;
713 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
714 command, namestr(&dgram->source_name),
715 inet_ntoa(p->ip), namestr(&dgram->dest_name)));