This commit was manufactured by cvs2svn to create tag
[Samba/gbeck.git] / source / namework.c
blobf4a9113cea7412cdbf52270e06e500b64159c039
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 extern int updatecount;
53 /* backup request types: which servers are to be included */
54 #define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
55 #define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL )
57 extern time_t StartupTime;
59 extern BOOL updatedlists;
61 /****************************************************************************
62 tell a server to become a backup browser
63 state - 0x01 become backup instead of master
64 - 0x02 remove all entries in browse list and become non-master
65 - 0x04 stop master browser service altogether. NT ignores this
66 **************************************************************************/
67 void reset_server(char *name, int state, struct in_addr ip)
69 char outbuf[20];
70 char *p;
72 bzero(outbuf,sizeof(outbuf));
73 p = outbuf;
75 CVAL(p,0) = ANN_ResetBrowserState;
76 CVAL(p,2) = state;
77 p += 2;
79 DEBUG(2,("sending reset to %s %s of state %d\n",
80 name,inet_ntoa(ip),state));
82 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
83 myname,name,0x20,0x1d,ip,*iface_ip(ip));
87 /****************************************************************************
88 tell a server to become a backup browser
89 **************************************************************************/
90 void tell_become_backup(void)
92 /* XXXX note: this function is currently unsuitable for use, as it
93 does not properly check that a server is in a fit state to become
94 a backup browser before asking it to be one.
97 struct subnet_record *d;
98 for (d = subnetlist; d; d = d->next)
100 struct work_record *work;
101 for (work = d->workgrouplist; work; work = work->next)
103 struct server_record *s;
104 int num_servers = 0;
105 int num_backups = 0;
107 for (s = work->serverlist; s; s = s->next)
109 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
111 num_servers++;
113 if (strequal(myname, s->serv.name)) continue;
115 if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
116 num_backups++;
117 continue;
120 if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
122 if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
124 DEBUG(3,("num servers: %d num backups: %d\n",
125 num_servers, num_backups));
127 /* make first server a backup server. thereafter make every
128 tenth server a backup server */
129 if (num_backups != 0 && (num_servers+9) / num_backups > 10)
131 continue;
134 DEBUG(2,("sending become backup to %s %s for %s\n",
135 s->serv.name, inet_ntoa(d->bcast_ip),
136 work->work_group));
138 /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
139 do_announce_request(s->serv.name, work->work_group,
140 ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
147 /*******************************************************************
148 same context: scope. should check name_type as well, and makes sure
149 we don't process messages from ourselves
150 ******************************************************************/
151 BOOL same_context(struct dgram_packet *dgram)
153 if (!strequal(dgram->dest_name .scope,scope )) return(True);
154 if ( strequal(dgram->source_name.name ,myname)) return(True);
156 return(False);
160 /*******************************************************************
161 process a domain announcement frame
163 Announce frames come in 3 types. Servers send host announcements
164 (command=1) to let the master browswer know they are
165 available. Master browsers send local master announcements
166 (command=15) to let other masters and backups that they are the
167 master. They also send domain announcements (command=12) to register
168 the domain
170 The comment field of domain announcements contains the master
171 browser name. The servertype is used by NetServerEnum to select
172 resources. We just have to pass it to smbd (via browser.dat) and let
173 the client choose using bit masks.
174 ******************************************************************/
175 static void process_announce(struct packet_struct *p,uint16 command,char *buf)
177 struct dgram_packet *dgram = &p->packet.dgram;
178 struct subnet_record *d = find_subnet(p->ip);
179 int update_count = CVAL(buf,0);
181 int ttl = IVAL(buf,1)/1000;
182 char *name = buf+5;
183 int osmajor=CVAL(buf,21);
184 int osminor=CVAL(buf,22);
185 uint32 servertype = IVAL(buf,23);
186 uint32 browse_type= CVAL(buf,27);
187 uint32 browse_sig = CVAL(buf,29);
188 char *comment = buf+31;
190 struct work_record *work;
191 char *work_name;
192 char *serv_name = dgram->source_name.name;
193 BOOL add = False;
195 comment[43] = 0;
197 DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
198 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
199 namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
200 servertype,browse_type,browse_sig,comment));
202 name[15] = 0;
204 if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
206 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
207 return;
210 if (command == ANN_DomainAnnouncement &&
211 ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
212 dgram->dest_name.name_type != 0x1))
214 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
215 command, inet_ntoa(p->ip), namestr(&dgram->dest_name)));
216 return;
219 if (!strequal(dgram->dest_name.scope,scope )) return;
221 if (command == ANN_DomainAnnouncement) {
222 /* XXXX if we are a master browser for the workgroup work_name,
223 then there is a local subnet configuration problem. only
224 we should be sending out such domain announcements, because
225 as the master browser, that is our job.
227 stop being a master browser, and force an election. this will
228 sort out the network problem. hopefully.
231 work_name = name;
232 add = True;
233 } else {
234 work_name = dgram->dest_name.name;
237 /* we need some way of finding out about new workgroups
238 that appear to be sending packets to us. The name_type checks make
239 sure we don't add host names as workgroups */
240 if (command == ANN_HostAnnouncement &&
241 (dgram->dest_name.name_type == 0x1d ||
242 dgram->dest_name.name_type == 0x1e))
243 add = True;
245 DEBUG(4,("search for workgroup: %s (add? %s)\n",
246 work_name, BOOLSTR(add)));
248 if (!(work = find_workgroupstruct(d, work_name,add)))
249 return;
251 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
253 ttl = GET_TTL(ttl);
255 /* add them to our browse list, and update the browse.dat file */
256 add_server_entry(d,work,name,servertype,ttl,comment,True);
257 updatedlists = True;
259 #if 0
260 /* the tell become backup code is broken, no great harm is done by
261 disabling it */
262 tell_become_backup();
263 #endif
265 /* get the local_only browse list from the local master and add it
266 to ours. */
267 if (command == ANN_LocalMasterAnnouncement)
269 add_browser_entry(serv_name,dgram->dest_name.name_type,
270 work->work_group,30,p->ip,True);
274 /*******************************************************************
275 process a master announcement frame
276 ******************************************************************/
277 static void process_master_announce(struct packet_struct *p,char *buf)
279 struct dgram_packet *dgram = &p->packet.dgram;
280 struct subnet_record *d = find_subnet(p->ip);
281 char *name = buf;
282 struct work_record *work;
283 name[15] = 0;
285 DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
287 if (same_context(dgram)) return;
289 if (!d) return;
291 if (!lp_domain_master()) return;
293 for (work = d->workgrouplist; work; work = work->next)
295 if (AM_MASTER(work))
297 /* merge browse lists with them */
298 add_browser_entry(name,0x1b, work->work_group,30,p->ip,True);
303 /*******************************************************************
304 process a receive backup list request
306 we receive a list of servers, and we attempt to locate them all on
307 our local subnet, and sync browse lists with them on the workgroup
308 they are said to be in.
310 XXXX NOTE: this function is in overdrive. it should not really do
311 half of what it actually does (it should pick _one_ name from the
312 list received and sync with it at regular intervals, rather than
313 sync with them all only once!)
315 ******************************************************************/
316 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
318 struct dgram_packet *dgram = &p->packet.dgram;
319 int count = CVAL(buf,0);
320 uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
321 char *buf1;
323 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
324 namestr(&dgram->dest_name), inet_ntoa(p->ip),
325 count, info));
327 if (same_context(dgram)) return;
329 if (count <= 0) return;
331 /* go through the list of servers attempting to sync browse lists */
332 for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
334 struct in_addr back_ip;
335 /* struct subnet_record *d; */
337 DEBUG(4,("Searching for backup browser %s at %s...\n",
338 buf1, inet_ntoa(p->ip)));
340 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
341 approach is to use reply_name_query functionality to find the name */
343 back_ip = *interpret_addr2(buf1);
345 if (zero_ip(back_ip))
347 DEBUG(4,("Failed to find backup browser server using DNS\n"));
348 continue;
351 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
352 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
354 #if 0
355 /* XXXX function needs work */
356 continue;
358 if ((d = find_subnet(back_ip)))
360 struct subnet_record *d1;
361 for (d1 = subnetlist; d1; d1 = d1->next)
363 struct work_record *work;
364 for (work = d1->workgrouplist; work; work = work->next)
366 if (work->token == 0 /* token */)
368 queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
369 work->work_group,0x1d,
370 0,0,0,NULL,NULL,
371 False,False,back_ip,back_ip);
372 return;
377 #endif
382 /****************************************************************************
383 send a backup list response.
384 **************************************************************************/
385 static void send_backup_list(char *work_name, struct nmb_name *src_name,
386 int token, uint32 info,
387 int name_type, struct in_addr ip)
389 char outbuf[1024];
390 char *p, *countptr, *nameptr;
391 int count = 0;
392 char *theirname = src_name->name;
394 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
395 work_name, inet_ntoa(ip),
396 myname,0x0,theirname,0x0));
398 if (name_type == 0x1d)
400 DEBUG(4,("master browsers: "));
402 else if (name_type == 0x1b)
404 DEBUG(4,("domain controllers: "));
406 else
408 DEBUG(0,("backup request for unknown type %0x\n", name_type));
409 return;
412 bzero(outbuf,sizeof(outbuf));
413 p = outbuf;
415 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
417 p++;
418 countptr = p;
420 SIVAL(p,1,info); /* the sender's unique info */
422 p += 5;
424 nameptr = p;
426 #if 0
428 for (d = subnetlist; d; d = d->next)
430 struct work_record *work;
432 for (work = d->workgrouplist; work; work = work->next)
434 struct server_record *s;
436 if (!strequal(work->work_group, work_name)) continue;
438 for (s = work->serverlist; s; s = s->next)
440 BOOL found = False;
441 char *n;
443 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
445 for (n = nameptr; n < p; n = skip_string(n, 1))
447 if (strequal(n, s->serv.name)) found = True;
450 if (found) continue; /* exclude names already added */
452 /* workgroup request: include all backup browsers in the list */
453 /* domain request: include all domain members in the list */
455 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
456 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
458 DEBUG(4, ("%s ", s->serv.name));
460 count++;
461 strcpy(p,s->serv.name);
462 strupper(p);
463 p = skip_string(p,1);
469 #endif
471 count++;
472 strcpy(p,myname);
473 strupper(p);
474 p = skip_string(p,1);
476 if (count == 0)
478 DEBUG(4, ("none\n"));
480 else
482 DEBUG(4, (" - count %d\n", count));
485 CVAL(countptr, 0) = count;
488 int len = PTR_DIFF(p, outbuf);
489 debug_browse_data(outbuf, len);
491 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
492 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
496 /*******************************************************************
497 process a send backup list request
499 A client sends a backup list request to ask for a list of servers on
500 the net that maintain server lists for a domain. A server is then
501 chosen from this list to send NetServerEnum commands to to list
502 available servers.
504 Currently samba only sends back one name in the backup list, its
505 own. For larger nets we'll have to add backups and send "become
506 backup" requests occasionally.
507 ******************************************************************/
508 static void process_send_backup_list(struct packet_struct *p,char *buf)
510 struct dgram_packet *dgram = &p->packet.dgram;
511 struct in_addr ip = dgram->header.source_ip;
512 struct subnet_record *d;
513 struct work_record *work;
515 int token = CVAL(buf,0); /* sender's key index for the workgroup */
516 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
517 int name_type = dgram->dest_name.name_type;
519 if (same_context(dgram)) return;
521 if (name_type != 0x1b && name_type != 0x1d) {
522 DEBUG(0,("backup request to wrong type %d from %s\n",
523 name_type,inet_ntoa(ip)));
524 return;
527 for (d = subnetlist; d; d = d->next)
529 for (work = d->workgrouplist; work; work = work->next)
531 if (strequal(work->work_group, dgram->dest_name.name))
533 DEBUG(2,("sending backup list to %s %s id=%x\n",
534 namestr(&dgram->dest_name),inet_ntoa(ip),info));
536 send_backup_list(work->work_group,&dgram->source_name,
537 token,info,name_type,ip);
538 return;
545 /*******************************************************************
546 process a reset browser state
548 diagnostic packet:
549 0x1 - stop being a master browser and become a backup browser.
550 0x2 - discard browse lists, stop being a master browser, try again.
551 0x4 - stop being a master browser forever. no way. ain't gonna.
553 ******************************************************************/
554 static void process_reset_browser(struct packet_struct *p,char *buf)
556 struct dgram_packet *dgram = &p->packet.dgram;
557 int state = CVAL(buf,0);
559 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
560 namestr(&dgram->dest_name), state));
562 /* stop being a master but still deal with being a backup browser */
563 if (state & 0x1)
565 struct subnet_record *d;
566 for (d = subnetlist; d; d = d->next)
568 struct work_record *work;
569 for (work = d->workgrouplist; work; work = work->next)
571 if (AM_MASTER(work))
573 become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
579 /* XXXX documentation inconsistency: the above description does not
580 exactly tally with what is implemented for state & 0x2
583 /* totally delete all servers and start afresh */
584 if (state & 0x2)
586 struct subnet_record *d;
587 for (d = subnetlist; d; d = d->next)
589 struct work_record *work;
590 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
592 add_my_subnets(lp_workgroup());
595 /* stop browsing altogether. i don't think this is a good idea! */
596 if (state & 0x4)
598 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
602 /*******************************************************************
603 process a announcement request
605 clients send these when they want everyone to send an announcement
606 immediately. This can cause quite a storm of packets!
607 ******************************************************************/
608 static void process_announce_request(struct packet_struct *p,char *buf)
610 struct dgram_packet *dgram = &p->packet.dgram;
611 struct work_record *work;
612 struct in_addr ip = dgram->header.source_ip;
613 struct subnet_record *d = find_subnet(ip);
614 int token = CVAL(buf,0);
615 char *name = buf+1;
617 name[15] = 0;
619 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
620 name,namestr(&dgram->dest_name), token));
622 if (strequal(dgram->source_name.name,myname)) return;
624 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
625 this workgroup before announcing, particularly as we only
626 respond on local interfaces anyway.
628 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
631 if (!d) return;
633 for (work = d->workgrouplist; work; work = work->next)
635 /* XXXX BUG: the destination name type should also be checked,
636 not just the name. e.g if the name is WORKGROUP(0x1d) then
637 we should only respond if we own that name */
639 if (strequal(dgram->dest_name.name,work->work_group))
641 work->needannounce = True;
648 /****************************************************************************
649 process a browse frame
650 ****************************************************************************/
651 void process_browse_packet(struct packet_struct *p,char *buf,int len)
653 int command = CVAL(buf,0);
654 switch (command)
656 case ANN_HostAnnouncement:
657 case ANN_DomainAnnouncement:
658 case ANN_LocalMasterAnnouncement:
660 debug_browse_data(buf, len);
661 process_announce(p,command,buf+1);
662 break;
665 case ANN_AnnouncementRequest:
667 process_announce_request(p,buf+1);
668 break;
671 case ANN_Election:
673 process_election(p,buf+1);
674 break;
677 case ANN_GetBackupListReq:
679 debug_browse_data(buf, len);
680 process_send_backup_list(p,buf+1);
681 break;
684 case ANN_GetBackupListResp:
686 debug_browse_data(buf, len);
687 process_rcv_backup_list(p, buf+1);
688 break;
691 case ANN_ResetBrowserState:
693 process_reset_browser(p, buf+1);
694 break;
697 case ANN_MasterAnnouncement:
699 process_master_announce(p,buf+1);
700 break;
703 default:
705 struct dgram_packet *dgram = &p->packet.dgram;
706 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
707 command, namestr(&dgram->source_name),
708 inet_ntoa(p->ip), namestr(&dgram->dest_name)));