updating documentation to reflect code a little bit.
[Samba.git] / source / namework.c
blob74c567fa748116c342072c4fe47c07d94f3e078e
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 /* get the local_only browse list from the local master and add it to ours. */
288 if (command == ANN_LocalMasterAnnouncement)
290 add_browser_entry(serv_name,dgram->dest_name.name_type,
291 work->work_group,30,ip,True);
295 /*******************************************************************
296 process a master announcement frame
297 ******************************************************************/
298 static void process_master_announce(struct packet_struct *p,char *buf)
300 struct dgram_packet *dgram = &p->packet.dgram;
301 struct in_addr ip = dgram->header.source_ip;
302 struct subnet_record *d = find_subnet(ip);
303 struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
304 char *name = buf;
305 struct work_record *work;
306 name[15] = 0;
308 DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip)));
310 if (same_context(dgram)) return;
312 if (!d || !mydomain) return;
314 if (!lp_domain_master()) return;
316 for (work = mydomain->workgrouplist; work; work = work->next)
318 if (AM_MASTER(work))
320 /* merge browse lists with them */
321 add_browser_entry(name,0x1b, work->work_group,30,ip,True);
326 /*******************************************************************
327 process a receive backup list request
329 we receive a list of servers, and we attempt to locate them all on
330 our local subnet, and sync browse lists with them on the workgroup
331 they are said to be in.
333 XXXX NOTE: this function is in overdrive. it should not really do
334 half of what it actually does (it should pick _one_ name from the
335 list received and sync with it at regular intervals, rather than
336 sync with them all only once!)
338 ******************************************************************/
339 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
341 struct dgram_packet *dgram = &p->packet.dgram;
342 struct in_addr ip = dgram->header.source_ip;
343 int count = CVAL(buf,0);
344 uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
345 char *buf1;
347 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
348 namestr(&dgram->dest_name), inet_ntoa(ip),
349 count, info));
351 if (same_context(dgram)) return;
353 if (count <= 0) return;
355 /* go through the list of servers attempting to sync browse lists */
356 for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
358 struct in_addr back_ip;
359 struct subnet_record *d;
361 DEBUG(4,("Searching for backup browser %s at %s...\n",
362 buf1, inet_ntoa(ip)));
364 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
365 approach is to use reply_name_query functionality to find the name */
367 back_ip = *interpret_addr2(buf1);
369 if (zero_ip(back_ip))
371 DEBUG(4,("Failed to find backup browser server using DNS\n"));
372 continue;
375 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
376 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
378 /* XXXX function needs work */
379 continue;
381 if ((d = find_subnet(back_ip)))
383 struct subnet_record *d1;
384 for (d1 = subnetlist; d1; d1 = d1->next)
386 struct work_record *work;
387 for (work = d1->workgrouplist; work; work = work->next)
389 if (work->token == 0 /* token */)
391 queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
392 work->work_group,0x1d,
393 0,0,0,NULL,NULL,
394 False,False,back_ip,back_ip);
395 return;
404 /****************************************************************************
405 send a backup list response.
406 **************************************************************************/
407 static void send_backup_list(char *work_name, struct nmb_name *src_name,
408 int token, uint32 info,
409 int name_type, struct in_addr ip)
411 char outbuf[1024];
412 char *p, *countptr, *nameptr;
413 int count = 0;
414 char *theirname = src_name->name;
416 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
417 work_name, inet_ntoa(ip),
418 myname,0x0,theirname,0x0));
420 if (name_type == 0x1d)
422 DEBUG(4,("master browsers: "));
424 else if (name_type == 0x1b)
426 DEBUG(4,("domain controllers: "));
428 else
430 DEBUG(0,("backup request for unknown type %0x\n", name_type));
431 return;
434 bzero(outbuf,sizeof(outbuf));
435 p = outbuf;
437 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
439 p++;
440 countptr = p;
442 SIVAL(p,1,info); /* the sender's unique info */
444 p += 5;
446 nameptr = p;
448 #if 0
450 for (d = subnetlist; d; d = d->next)
452 struct work_record *work;
454 for (work = d->workgrouplist; work; work = work->next)
456 struct server_record *s;
458 if (!strequal(work->work_group, work_name)) continue;
460 for (s = work->serverlist; s; s = s->next)
462 BOOL found = False;
463 char *n;
465 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
467 for (n = nameptr; n < p; n = skip_string(n, 1))
469 if (strequal(n, s->serv.name)) found = True;
472 if (found) continue; /* exclude names already added */
474 /* workgroup request: include all backup browsers in the list */
475 /* domain request: include all domain members in the list */
477 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
478 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
480 DEBUG(4, ("%s ", s->serv.name));
482 count++;
483 strcpy(p,s->serv.name);
484 strupper(p);
485 p = skip_string(p,1);
491 #endif
493 count++;
494 strcpy(p,myname);
495 strupper(p);
496 p = skip_string(p,1);
498 if (count == 0)
500 DEBUG(4, ("none\n"));
502 else
504 DEBUG(4, (" - count %d\n", count));
507 CVAL(countptr, 0) = count;
510 int len = PTR_DIFF(p, outbuf);
511 debug_browse_data(outbuf, len);
513 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
514 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
518 /*******************************************************************
519 process a send backup list request
521 A client sends a backup list request to ask for a list of servers on
522 the net that maintain server lists for a domain. A server is then
523 chosen from this list to send NetServerEnum commands to to list
524 available servers.
526 Currently samba only sends back one name in the backup list, its
527 own. For larger nets we'll have to add backups and send "become
528 backup" requests occasionally.
529 ******************************************************************/
530 static void process_send_backup_list(struct packet_struct *p,char *buf)
532 struct dgram_packet *dgram = &p->packet.dgram;
533 struct in_addr ip = dgram->header.source_ip;
534 struct subnet_record *d;
535 struct work_record *work;
537 int token = CVAL(buf,0); /* sender's key index for the workgroup */
538 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
539 int name_type = dgram->dest_name.name_type;
541 if (same_context(dgram)) return;
543 if (name_type != 0x1b && name_type != 0x1d) {
544 DEBUG(0,("backup request to wrong type %d from %s\n",
545 name_type,inet_ntoa(ip)));
546 return;
549 for (d = subnetlist; d; d = d->next)
551 for (work = d->workgrouplist; work; work = work->next)
553 if (strequal(work->work_group, dgram->dest_name.name))
555 DEBUG(2,("sending backup list to %s %s id=%x\n",
556 namestr(&dgram->dest_name),inet_ntoa(ip),info));
558 send_backup_list(work->work_group,&dgram->source_name,
559 token,info,name_type,ip);
560 return;
567 /*******************************************************************
568 process a reset browser state
570 diagnostic packet:
571 0x1 - stop being a master browser and become a backup browser.
572 0x2 - discard browse lists, stop being a master browser, try again.
573 0x4 - stop being a master browser forever. no way. ain't gonna.
575 ******************************************************************/
576 static void process_reset_browser(struct packet_struct *p,char *buf)
578 struct dgram_packet *dgram = &p->packet.dgram;
579 int state = CVAL(buf,0);
581 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
582 namestr(&dgram->dest_name), state));
584 /* stop being a master but still deal with being a backup browser */
585 if (state & 0x1)
587 struct subnet_record *d;
588 for (d = subnetlist; d; d = d->next)
590 struct work_record *work;
591 for (work = d->workgrouplist; work; work = work->next)
593 if (AM_MASTER(work))
595 become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
601 /* XXXX documentation inconsistency: the above description does not
602 exactly tally with what is implemented for state & 0x2
605 /* totally delete all servers and start afresh */
606 if (state & 0x2)
608 struct subnet_record *d;
609 for (d = subnetlist; d; d = d->next)
611 struct work_record *work;
612 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
614 add_my_subnets(lp_workgroup());
617 /* stop browsing altogether. i don't think this is a good idea! */
618 if (state & 0x4)
620 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
624 /*******************************************************************
625 process a announcement request
627 clients send these when they want everyone to send an announcement
628 immediately. This can cause quite a storm of packets!
629 ******************************************************************/
630 static void process_announce_request(struct packet_struct *p,char *buf)
632 struct dgram_packet *dgram = &p->packet.dgram;
633 struct work_record *work;
634 struct in_addr ip = dgram->header.source_ip;
635 struct subnet_record *d = find_subnet(ip);
636 int token = CVAL(buf,0);
637 char *name = buf+1;
639 name[15] = 0;
641 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
642 name,namestr(&dgram->dest_name), token));
644 if (strequal(dgram->source_name.name,myname)) return;
646 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
647 this workgroup before announcing, particularly as we only
648 respond on local interfaces anyway.
650 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
653 if (!d) return;
655 for (work = d->workgrouplist; work; work = work->next)
657 /* XXXX BUG: the destination name type should also be checked,
658 not just the name. e.g if the name is WORKGROUP(0x1d) then
659 we should only respond if we own that name */
661 if (strequal(dgram->dest_name.name,work->work_group))
663 work->needannounce = True;
669 /****************************************************************************
670 depending on what announce has been made, we are only going to
671 accept certain types of name announce. XXXX untested code
673 check listening name type
674 ****************************************************************************/
675 BOOL listening_type(struct packet_struct *p, int command)
677 struct dgram_packet *dgram = &p->packet.dgram;
678 int type = dgram->dest_name.name_type;
680 switch (command)
682 case ANN_HostAnnouncement:
684 if (type != 0x0 || type != 0x20) return (False);
685 break;
688 case ANN_AnnouncementRequest:
690 return (True);
691 break;
694 case ANN_Election:
696 return (True);
697 break;
700 case ANN_GetBackupListReq:
702 return (True);
703 break;
706 case ANN_GetBackupListResp:
708 return (True);
709 break;
712 case ANN_DomainAnnouncement:
714 if (type != 0x1b || type != 0x1c) return (False);
715 break;
718 case ANN_MasterAnnouncement:
720 if (type != 0x1d) return (False);
721 break;
724 case ANN_LocalMasterAnnouncement:
726 if (type != 0x1c || type != 0x1d) return (False);
727 break;
730 return (True); /* we're not dealing with unknown packet types */
734 /****************************************************************************
735 process a browse frame
736 ****************************************************************************/
737 void process_browse_packet(struct packet_struct *p,char *buf,int len)
739 int command = CVAL(buf,0);
740 switch (command)
742 case ANN_HostAnnouncement:
743 case ANN_DomainAnnouncement:
744 case ANN_LocalMasterAnnouncement:
746 debug_browse_data(buf, len);
747 process_announce(p,command,buf+1);
748 break;
751 case ANN_AnnouncementRequest:
753 process_announce_request(p,buf+1);
754 break;
757 case ANN_Election:
759 process_election(p,buf+1);
760 break;
763 case ANN_GetBackupListReq:
765 debug_browse_data(buf, len);
766 process_send_backup_list(p,buf+1);
767 break;
770 case ANN_GetBackupListResp:
772 debug_browse_data(buf, len);
773 process_rcv_backup_list(p, buf+1);
774 break;
777 case ANN_ResetBrowserState:
779 process_reset_browser(p, buf+1);
780 break;
783 case ANN_MasterAnnouncement:
785 process_master_announce(p,buf+1);
786 break;
789 default:
791 struct dgram_packet *dgram = &p->packet.dgram;
792 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
793 command, namestr(&dgram->source_name),
794 inet_ntoa(p->ip), namestr(&dgram->dest_name)));