lots of changes to nmbd
[Samba.git] / source / namework.c
blob4329e6f197ad3d1ba7c13961bd7ae56cd47225e7
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
21 Revision History:
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
28 #include "includes.h"
30 extern int ClientNMB;
31 extern int ClientDGRAM;
33 #define TEST_CODE /* want to debug unknown browse packets */
35 extern int DEBUGLEVEL;
36 extern pstring scope;
37 extern BOOL CanRecurse;
39 extern pstring myname;
41 extern int ClientNMB;
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)
77 char outbuf[20];
78 char *p;
80 bzero(outbuf,sizeof(outbuf));
81 p = outbuf;
83 CVAL(p,0) = ANN_ResetBrowserState;
84 CVAL(p,2) = state;
85 p += 2;
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;
112 int num_servers = 0;
113 int num_backups = 0;
115 for (s = work->serverlist; s; s = s->next)
117 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
119 num_servers++;
121 if (strequal(myname, s->serv.name)) continue;
123 if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
124 num_backups++;
125 continue;
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)
139 continue;
142 DEBUG(2,("sending become backup to %s %s for %s\n",
143 s->serv.name, inet_ntoa(d->bcast_ip),
144 work->work_group));
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);
164 return(False);
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))
177 return(True);
180 return(False);
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
192 the domain
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;
207 char *name = buf+5;
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;
216 char *work_name;
217 char *serv_name = dgram->source_name.name;
218 BOOL add = False;
220 comment[43] = 0;
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));
227 name[15] = 0;
229 if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
231 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
232 return;
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)));
241 return;
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.
256 work_name = name;
257 add = True;
258 } else {
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))
268 add = True;
270 if (!(work = find_workgroupstruct(d, work_name,add)))
271 return;
273 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
275 ttl = GET_TTL(ttl);
277 /* add them to our browse list, and update the browse.dat file */
278 add_server_entry(d,work,name,servertype,ttl,comment,True);
279 updatedlists = True;
281 #if 0
282 /* the tell become backup code is broken, no great harm is done by
283 disabling it */
284 tell_become_backup();
285 #endif
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.
292 possibly.
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));
309 char *name = buf;
310 struct work_record *work;
311 name[15] = 0;
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)
323 if (AM_MASTER(work))
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 */
350 char *buf1;
352 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
353 namestr(&dgram->dest_name), inet_ntoa(ip),
354 count, info));
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"));
377 continue;
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 */
384 continue;
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);
399 return;
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;
416 char outbuf[1024];
417 char *p, *countptr, *nameptr;
418 int count = 0;
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: "));
433 else
435 DEBUG(0,("backup request for unknown type %0x\n", name_type));
436 return;
439 bzero(outbuf,sizeof(outbuf));
440 p = outbuf;
442 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
444 p++;
445 countptr = p;
447 SIVAL(p,1,info); /* the sender's unique info */
449 p += 5;
451 nameptr = p;
453 #if 0
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)
467 BOOL found = False;
468 char *n;
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));
487 count++;
488 strcpy(p,s->serv.name);
489 strupper(p);
490 p = skip_string(p,1);
496 #endif
498 count++;
499 strcpy(p,myname);
500 strupper(p);
501 p = skip_string(p,1);
503 if (count == 0)
505 DEBUG(4, ("none\n"));
507 else
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
529 available servers.
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)));
551 return;
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);
565 return;
572 /*******************************************************************
573 process a reset browser state
575 diagnostic packet:
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 */
590 if (state & 0x1)
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)
598 if (AM_MASTER(work))
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 */
611 if (state & 0x2)
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! */
623 if (state & 0x4)
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);
642 char *name = buf+1;
644 name[15] = 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; ???
658 if (!d) 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;
687 switch (command)
689 case ANN_HostAnnouncement:
691 if (type != 0x0 || type != 0x20) return (False);
692 break;
695 case ANN_AnnouncementRequest:
697 return (True);
698 break;
701 case ANN_Election:
703 return (True);
704 break;
707 case ANN_GetBackupListReq:
709 return (True);
710 break;
713 case ANN_GetBackupListResp:
715 return (True);
716 break;
719 case ANN_DomainAnnouncement:
721 if (type != 0x1b || type != 0x1c) return (False);
722 break;
725 case ANN_MasterAnnouncement:
727 if (type != 0x1d) return (False);
728 break;
731 case ANN_LocalMasterAnnouncement:
733 if (type != 0x1c || type != 0x1d) return (False);
734 break;
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);
747 switch (command)
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);
755 break;
758 case ANN_AnnouncementRequest:
760 process_announce_request(p,buf+1);
761 break;
764 case ANN_Election:
766 process_election(p,buf+1);
767 break;
770 case ANN_GetBackupListReq:
772 debug_browse_data(buf, len);
773 process_send_backup_list(p,buf+1);
774 break;
777 case ANN_GetBackupListResp:
779 debug_browse_data(buf, len);
780 process_rcv_backup_list(p, buf+1);
781 break;
784 case ANN_ResetBrowserState:
786 process_reset_browser(p, buf+1);
787 break;
790 case ANN_MasterAnnouncement:
792 process_master_announce(p,buf+1);
793 break;
796 default:
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)));