sorted out various timer delay bugs: nameannounce.c nameserv.c
[Samba.git] / source / namework.c
blob85a07a7dc94f39e5bfe1ef4a1fd3f492da9b3781
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;
68 /****************************************************************************
69 tell a server to become a backup browser
70 state - 0x01 become backup instead of master
71 - 0x02 remove all entries in browse list and become non-master
72 - 0x04 stop master browser service altogether. NT ignores this
73 **************************************************************************/
74 void reset_server(char *name, int state, struct in_addr ip)
76 char outbuf[20];
77 char *p;
79 bzero(outbuf,sizeof(outbuf));
80 p = outbuf;
82 CVAL(p,0) = ANN_ResetBrowserState;
83 CVAL(p,2) = state;
84 p += 2;
86 DEBUG(2,("sending reset to %s %s of state %d\n",
87 name,inet_ntoa(ip),state));
89 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
90 myname,name,0x20,0x1d,ip,*iface_ip(ip));
94 /****************************************************************************
95 tell a server to become a backup browser
96 **************************************************************************/
97 void tell_become_backup(void)
99 /* XXXX note: this function is currently unsuitable for use, as it
100 does not properly check that a server is in a fit state to become
101 a backup browser before asking it to be one.
104 struct subnet_record *d;
105 for (d = subnetlist; d; d = d->next)
107 struct work_record *work;
108 for (work = d->workgrouplist; work; work = work->next)
110 struct server_record *s;
111 int num_servers = 0;
112 int num_backups = 0;
114 for (s = work->serverlist; s; s = s->next)
116 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
118 num_servers++;
120 if (strequal(myname, s->serv.name)) continue;
122 if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
123 num_backups++;
124 continue;
127 if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
129 if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
131 DEBUG(3,("num servers: %d num backups: %d\n",
132 num_servers, num_backups));
134 /* make first server a backup server. thereafter make every
135 tenth server a backup server */
136 if (num_backups != 0 && (num_servers+9) / num_backups > 10)
138 continue;
141 DEBUG(2,("sending become backup to %s %s for %s\n",
142 s->serv.name, inet_ntoa(d->bcast_ip),
143 work->work_group));
145 /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
146 do_announce_request(s->serv.name, work->work_group,
147 ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
154 /*******************************************************************
155 same context: scope. should check name_type as well, and makes sure
156 we don't process messages from ourselves
157 ******************************************************************/
158 BOOL same_context(struct dgram_packet *dgram)
160 if (!strequal(dgram->dest_name .scope,scope )) return(True);
161 if ( strequal(dgram->source_name.name ,myname)) return(True);
163 return(False);
167 /*******************************************************************
168 am I listening on a name. XXXX check the type of name as well.
169 ******************************************************************/
170 BOOL listening_name(struct work_record *work, struct nmb_name *n)
172 if (strequal(n->name,myname) ||
173 strequal(n->name,work->work_group) ||
174 strequal(n->name,MSBROWSE))
176 return(True);
179 return(False);
183 /*******************************************************************
184 process a domain announcement frame
186 Announce frames come in 3 types. Servers send host announcements
187 (command=1) to let the master browswer know they are
188 available. Master browsers send local master announcements
189 (command=15) to let other masters and backups that they are the
190 master. They also send domain announcements (command=12) to register
191 the domain
193 The comment field of domain announcements contains the master
194 browser name. The servertype is used by NetServerEnum to select
195 resources. We just have to pass it to smbd (via browser.dat) and let
196 the client choose using bit masks.
197 ******************************************************************/
198 static void process_announce(struct packet_struct *p,int command,char *buf)
200 struct dgram_packet *dgram = &p->packet.dgram;
201 struct in_addr ip = dgram->header.source_ip;
202 struct subnet_record *d = find_subnet(ip);
203 int update_count = CVAL(buf,0);
204 int ttl = IVAL(buf,1)/1000;
205 char *name = buf+5;
206 int osmajor=CVAL(buf,21);
207 int osminor=CVAL(buf,22);
208 uint32 servertype = IVAL(buf,23);
209 char *comment = buf+31;
210 struct work_record *work;
211 char *work_name;
212 char *serv_name = dgram->source_name.name;
213 BOOL add = False;
215 comment[43] = 0;
217 DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
218 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n",
219 namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
220 servertype,comment));
222 name[15] = 0;
224 if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
226 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
227 return;
230 if (command == ANN_DomainAnnouncement &&
231 ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
232 dgram->dest_name.name_type != 0x1))
234 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
235 command, inet_ntoa(ip), namestr(&dgram->dest_name)));
236 return;
239 if (same_context(dgram)) return;
241 if (command == ANN_DomainAnnouncement) {
242 /* XXXX if we are a master browser for the workgroup work_name,
243 then there is a local subnet configuration problem. only
244 we should be sending out such domain announcements, because
245 as the master browser, that is our job.
247 stop being a master browser, and force an election. this will
248 sort out the network problem. hopefully.
251 work_name = name;
252 } else {
253 work_name = dgram->dest_name.name;
256 /* we need some way of finding out about new workgroups
257 that appear to be sending packets to us. The name_type checks make
258 sure we don't add host names as workgroups */
259 if (command == ANN_HostAnnouncement &&
260 (dgram->dest_name.name_type == 0x1d ||
261 dgram->dest_name.name_type == 0x1e))
262 add = True;
264 if (!(work = find_workgroupstruct(d, work_name,add)))
265 return;
267 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
269 ttl = GET_TTL(ttl);
271 /* add them to our browse list */
272 add_server_entry(d,work,name,servertype,ttl,comment,True);
274 #if 0
275 /* the tell become backup code is broken, no great harm is done by
276 disabling it */
277 tell_become_backup();
278 #endif
280 /* XXXX over-kill: i don't think we should really be doing this,
281 but it doesn't do much harm other than to add extra network
282 traffic. to be more precise, we should (possibly) only
283 sync browse lists with a host that sends an
284 ANN_LocalMasterAnnouncement or an ANN_DomainAnnouncement.
285 possibly.
288 /* get their browse list from them and add it to ours. */
289 add_browser_entry(serv_name,dgram->dest_name.name_type,
290 work->work_group,30,ip);
293 /*******************************************************************
294 process a master announcement frame
295 ******************************************************************/
296 static void process_master_announce(struct packet_struct *p,char *buf)
298 struct dgram_packet *dgram = &p->packet.dgram;
299 struct in_addr ip = dgram->header.source_ip;
300 struct subnet_record *d = find_subnet(ip);
301 struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
302 char *name = buf;
303 struct work_record *work;
304 name[15] = 0;
306 DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip)));
308 if (same_context(dgram)) return;
310 if (!d || !mydomain) return;
312 if (!lp_domain_master()) return;
314 for (work = mydomain->workgrouplist; work; work = work->next)
316 if (AM_MASTER(work))
318 /* merge browse lists with them */
319 add_browser_entry(name,0x1b, work->work_group,30,ip);
324 /*******************************************************************
325 process a receive backup list request
327 we receive a list of servers, and we attempt to locate them all on
328 our local subnet, and sync browse lists with them on the workgroup
329 they are said to be in.
331 XXXX NOTE: this function is in overdrive. it should not really do
332 half of what it actually does (it should pick _one_ name from the
333 list received and sync with it at regular intervals, rather than
334 sync with them all only once!)
336 ******************************************************************/
337 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
339 struct dgram_packet *dgram = &p->packet.dgram;
340 struct in_addr ip = dgram->header.source_ip;
341 int count = CVAL(buf,0);
342 int Index = IVAL(buf,1); /* caller's index representing workgroup */
343 char *buf1;
345 DEBUG(3,("Receive Backup ack for %s from %s total=%d index=%d\n",
346 namestr(&dgram->dest_name), inet_ntoa(ip),
347 count, Index));
349 if (same_context(dgram)) return;
351 if (count <= 0) return;
353 /* go through the list of servers attempting to sync browse lists */
354 for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
356 struct in_addr back_ip;
357 struct subnet_record *d;
359 DEBUG(4,("Searching for backup browser %s at %s...\n",
360 buf1, inet_ntoa(ip)));
362 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
363 approach is to use reply_name_query functionality to find the name */
364 back_ip = *interpret_addr2(buf1);
366 if (zero_ip(back_ip))
368 DEBUG(4,("Failed to find backup browser server using DNS\n"));
369 continue;
372 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
374 if ((d = find_subnet(back_ip)))
376 struct subnet_record *d1;
377 for (d1 = subnetlist; d1; d1 = d1->next)
379 struct work_record *work;
380 for (work = d1->workgrouplist; work; work = work->next)
382 if (work->token == Index)
384 queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
385 work->work_group,0x1d,0,0,
386 False,False,back_ip,back_ip);
387 return;
396 /****************************************************************************
397 send a backup list response.
398 **************************************************************************/
399 static void send_backup_list(char *work_name, struct nmb_name *src_name,
400 int info_count, int token, int info,
401 int name_type, struct in_addr ip)
403 struct subnet_record *d;
404 char outbuf[1024];
405 char *p, *countptr, *nameptr;
406 int count = 0;
407 int i, j;
408 char *theirname = src_name->name;
410 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
411 work_name, inet_ntoa(ip),
412 myname,0x20,theirname,0x0));
414 if (name_type == 0x1d)
416 DEBUG(4,("master browsers: "));
418 else if (name_type == 0x1b)
420 DEBUG(4,("domain controllers: "));
422 else
424 DEBUG(0,("backup request for unknown type %0x\n", name_type));
425 return;
428 bzero(outbuf,sizeof(outbuf));
429 p = outbuf;
431 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
432 p++;
434 countptr = p; /* count pointer */
436 SSVAL(p,1,token); /* sender's workgroup index representation */
437 SSVAL(p,3,info); /* XXXX clueless: info, usually zero */
438 p += 5;
440 nameptr = p;
442 for (d = subnetlist; d; d = d->next)
444 struct work_record *work;
446 for (work = d->workgrouplist; work; work = work->next)
448 struct server_record *s;
450 if (!strequal(work->work_group, work_name)) continue;
452 for (s = work->serverlist; s; s = s->next)
454 BOOL found = False;
455 char *n;
457 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
459 for (n = nameptr; n < p; n = skip_string(n, 1))
461 if (strequal(n, s->serv.name)) found = True;
464 if (found) continue; /* exclude names already added */
466 /* workgroup request: include all backup browsers in the list */
467 /* domain request: include all domain members in the list */
469 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
470 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
472 DEBUG(4, ("%s ", s->serv.name));
474 count++;
475 strcpy(p,s->serv.name);
476 strupper(p);
477 p = skip_string(p,1);
483 if (count == 0)
485 DEBUG(4, ("none\n"));
486 return;
488 else
490 DEBUG(4, (" - count %d\n", count));
493 CVAL(countptr,0) = count; /* total number of backup browsers found */
496 int len = PTR_DIFF(p, outbuf);
498 for (i = 0; i < len; i+= 16)
500 DEBUG(4, ("%3x char ", i));
502 for (j = 0; j < 16; j++)
504 unsigned char x = outbuf[i+j];
505 if (x < 32 || x > 127) x = '.';
507 if (i+j >= len) break;
508 DEBUG(4, ("%c", x));
511 DEBUG(4, (" hex ", i));
513 for (j = 0; j < 16; j++)
515 if (i+j >= len) break;
516 DEBUG(4, (" %02x", outbuf[i+j]));
519 DEBUG(4, ("\n"));
523 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
524 myname,theirname,0x20,0x0,ip,*iface_ip(ip));
528 /*******************************************************************
529 process a send backup list request
531 A client sends a backup list request to ask for a list of servers on
532 the net that maintain server lists for a domain. A server is then
533 chosen from this list to send NetServerEnum commands to to list
534 available servers.
536 Currently samba only sends back one name in the backup list, its
537 own. For larger nets we'll have to add backups and send "become
538 backup" requests occasionally.
539 ******************************************************************/
540 static void process_send_backup_list(struct packet_struct *p,char *buf)
542 struct dgram_packet *dgram = &p->packet.dgram;
543 struct in_addr ip = dgram->header.source_ip;
544 struct subnet_record *d;
545 struct work_record *work;
547 int count = CVAL(buf,0);
548 int token = SVAL(buf,1); /* sender's key index for the workgroup? */
549 int info = SVAL(buf,3); /* XXXX don't know: some sort of info */
550 int name_type = dgram->dest_name.name_type;
552 if (same_context(dgram)) return;
554 if (count <= 0) return;
556 if (name_type != 0x1b && name_type != 0x1d) {
557 DEBUG(0,("backup request to wrong type %d from %s\n",
558 name_type,inet_ntoa(ip)));
559 return;
562 for (d = subnetlist; d; d = d->next)
564 for (work = d->workgrouplist; work; work = work->next)
566 if (strequal(work->work_group, dgram->dest_name.name))
568 DEBUG(2,("sending backup list to %s %s count=%d\n",
569 namestr(&dgram->dest_name),inet_ntoa(ip),count));
571 send_backup_list(work->work_group,&dgram->source_name,
572 count,token,info,name_type,ip);
573 return;
580 /*******************************************************************
581 process a reset browser state
583 diagnostic packet:
584 0x1 - stop being a master browser and become a backup browser.
585 0x2 - discard browse lists, stop being a master browser, try again.
586 0x4 - stop being a master browser forever. no way. ain't gonna.
588 ******************************************************************/
589 static void process_reset_browser(struct packet_struct *p,char *buf)
591 struct dgram_packet *dgram = &p->packet.dgram;
592 int state = CVAL(buf,0);
594 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
595 namestr(&dgram->dest_name), state));
597 /* stop being a master but still deal with being a backup browser */
598 if (state & 0x1)
600 struct subnet_record *d;
601 for (d = subnetlist; d; d = d->next)
603 struct work_record *work;
604 for (work = d->workgrouplist; work; work = work->next)
606 if (AM_MASTER(work))
608 become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
614 /* XXXX documentation inconsistency: the above description does not
615 exactly tally with what is implemented for state & 0x2
618 /* totally delete all servers and start afresh */
619 if (state & 0x2)
621 struct subnet_record *d;
622 for (d = subnetlist; d; d = d->next)
624 struct work_record *work;
625 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
627 add_my_subnets(lp_workgroup());
630 /* stop browsing altogether. i don't think this is a good idea! */
631 if (state & 0x4)
633 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
638 /*******************************************************************
639 process a announcement request
641 clients send these when they want everyone to send an announcement
642 immediately. This can cause quite a storm of packets!
643 ******************************************************************/
644 static void process_announce_request(struct packet_struct *p,char *buf)
646 struct dgram_packet *dgram = &p->packet.dgram;
647 struct work_record *work;
648 struct in_addr ip = dgram->header.source_ip;
649 struct subnet_record *d = find_subnet(ip);
650 int token = CVAL(buf,0);
651 char *name = buf+1;
653 name[15] = 0;
655 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
656 name,namestr(&dgram->dest_name), token));
658 if (strequal(dgram->source_name.name,myname)) return;
660 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
661 this workgroup before announcing, particularly as we only
662 respond on local interfaces anyway.
664 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
667 if (!d) return;
669 if (!d->my_interface) return;
671 for (work = d->workgrouplist; work; work = work->next)
673 /* XXXX BUG: the destination name type should also be checked,
674 not just the name. e.g if the name is WORKGROUP(0x1d) then
675 we should only respond if we own that name */
677 if (strequal(dgram->dest_name.name,work->work_group))
679 work->needannounce = True;
685 /****************************************************************************
686 depending on what announce has been made, we are only going to
687 accept certain types of name announce. XXXX untested code
689 check listening name type
690 ****************************************************************************/
691 BOOL listening_type(struct packet_struct *p, int command)
693 struct dgram_packet *dgram = &p->packet.dgram;
694 int type = dgram->dest_name.name_type;
696 switch (command)
698 case ANN_HostAnnouncement:
700 if (type != 0x0 || type != 0x20) return (False);
701 break;
704 case ANN_AnnouncementRequest:
706 return (True);
707 break;
710 case ANN_Election:
712 return (True);
713 break;
716 case ANN_GetBackupListReq:
718 return (True);
719 break;
722 case ANN_GetBackupListResp:
724 return (True);
725 break;
728 case ANN_DomainAnnouncement:
730 if (type != 0x1b || type != 0x1c) return (False);
731 break;
734 case ANN_MasterAnnouncement:
736 if (type != 0x1d) return (False);
737 break;
740 case ANN_LocalMasterAnnouncement:
742 if (type != 0x1c || type != 0x1d) return (False);
743 break;
746 return (True); /* we're not dealing with unknown packet types */
750 /****************************************************************************
751 process a browse frame
752 ****************************************************************************/
753 void process_browse_packet(struct packet_struct *p,char *buf,int len)
755 int command = CVAL(buf,0);
756 switch (command)
758 case ANN_HostAnnouncement:
759 case ANN_DomainAnnouncement:
760 case ANN_LocalMasterAnnouncement:
762 process_announce(p,command,buf+1);
763 break;
766 case ANN_AnnouncementRequest:
768 process_announce_request(p,buf+1);
769 break;
772 case ANN_Election:
774 process_election(p,buf+1);
775 break;
778 case ANN_GetBackupListReq:
780 process_send_backup_list(p,buf+1);
781 break;
784 case ANN_GetBackupListResp:
786 process_rcv_backup_list(p, buf+1);
787 break;
790 case ANN_ResetBrowserState:
792 process_reset_browser(p, buf+1);
793 break;
796 case ANN_MasterAnnouncement:
798 process_master_announce(p,buf+1);
799 break;
802 default:
804 struct dgram_packet *dgram = &p->packet.dgram;
805 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
806 command, namestr(&dgram->source_name),
807 inet_ntoa(p->ip), namestr(&dgram->dest_name)));