removed all of lukes recent changes. I need to do a p2 release but
[Samba.git] / source / namework.c
blob0380c1460affa2e7c693614af517ab41aae9a8b7
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 in_addr ip = dgram->header.source_ip;
179 struct subnet_record *d = find_subnet(ip);
180 int update_count = CVAL(buf,0);
182 int ttl = IVAL(buf,1)/1000;
183 char *name = buf+5;
184 int osmajor=CVAL(buf,21);
185 int osminor=CVAL(buf,22);
186 uint32 servertype = IVAL(buf,23);
187 uint32 browse_type= CVAL(buf,27);
188 uint32 browse_sig = CVAL(buf,29);
189 char *comment = buf+31;
191 struct work_record *work;
192 char *work_name;
193 char *serv_name = dgram->source_name.name;
194 BOOL add = False;
196 comment[43] = 0;
198 DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
199 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
200 namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
201 servertype,browse_type,browse_sig,comment));
203 name[15] = 0;
205 if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
207 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
208 return;
211 if (command == ANN_DomainAnnouncement &&
212 ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
213 dgram->dest_name.name_type != 0x1))
215 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
216 command, inet_ntoa(ip), namestr(&dgram->dest_name)));
217 return;
220 if (!strequal(dgram->dest_name.scope,scope )) return;
222 if (command == ANN_DomainAnnouncement) {
223 /* XXXX if we are a master browser for the workgroup work_name,
224 then there is a local subnet configuration problem. only
225 we should be sending out such domain announcements, because
226 as the master browser, that is our job.
228 stop being a master browser, and force an election. this will
229 sort out the network problem. hopefully.
232 work_name = name;
233 add = True;
234 } else {
235 work_name = dgram->dest_name.name;
238 /* we need some way of finding out about new workgroups
239 that appear to be sending packets to us. The name_type checks make
240 sure we don't add host names as workgroups */
241 if (command == ANN_HostAnnouncement &&
242 (dgram->dest_name.name_type == 0x1d ||
243 dgram->dest_name.name_type == 0x1e))
244 add = True;
246 if (!(work = find_workgroupstruct(d, work_name,add)))
247 return;
249 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
251 ttl = GET_TTL(ttl);
253 /* add them to our browse list, and update the browse.dat file */
254 add_server_entry(d,work,name,servertype,ttl,comment,True);
255 updatedlists = True;
257 #if 0
258 /* the tell become backup code is broken, no great harm is done by
259 disabling it */
260 tell_become_backup();
261 #endif
263 /* get the local_only browse list from the local master and add it
264 to ours. */
265 if (command == ANN_LocalMasterAnnouncement)
267 add_browser_entry(serv_name,dgram->dest_name.name_type,
268 work->work_group,30,ip,True);
272 /*******************************************************************
273 process a master announcement frame
274 ******************************************************************/
275 static void process_master_announce(struct packet_struct *p,char *buf)
277 struct dgram_packet *dgram = &p->packet.dgram;
278 struct in_addr ip = dgram->header.source_ip;
279 struct subnet_record *d = find_subnet(ip);
280 struct subnet_record *mydomain = find_subnet(*iface_bcast(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(ip)));
287 if (same_context(dgram)) return;
289 if (!d || !mydomain) return;
291 if (!lp_domain_master()) return;
293 for (work = mydomain->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,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 struct in_addr ip = dgram->header.source_ip;
320 int count = CVAL(buf,0);
321 uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
322 char *buf1;
324 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
325 namestr(&dgram->dest_name), inet_ntoa(ip),
326 count, info));
328 if (same_context(dgram)) return;
330 if (count <= 0) return;
332 /* go through the list of servers attempting to sync browse lists */
333 for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
335 struct in_addr back_ip;
336 struct subnet_record *d;
338 DEBUG(4,("Searching for backup browser %s at %s...\n",
339 buf1, inet_ntoa(ip)));
341 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
342 approach is to use reply_name_query functionality to find the name */
344 back_ip = *interpret_addr2(buf1);
346 if (zero_ip(back_ip))
348 DEBUG(4,("Failed to find backup browser server using DNS\n"));
349 continue;
352 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
353 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
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;
381 /****************************************************************************
382 send a backup list response.
383 **************************************************************************/
384 static void send_backup_list(char *work_name, struct nmb_name *src_name,
385 int token, uint32 info,
386 int name_type, struct in_addr ip)
388 char outbuf[1024];
389 char *p, *countptr, *nameptr;
390 int count = 0;
391 char *theirname = src_name->name;
393 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
394 work_name, inet_ntoa(ip),
395 myname,0x0,theirname,0x0));
397 if (name_type == 0x1d)
399 DEBUG(4,("master browsers: "));
401 else if (name_type == 0x1b)
403 DEBUG(4,("domain controllers: "));
405 else
407 DEBUG(0,("backup request for unknown type %0x\n", name_type));
408 return;
411 bzero(outbuf,sizeof(outbuf));
412 p = outbuf;
414 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
416 p++;
417 countptr = p;
419 SIVAL(p,1,info); /* the sender's unique info */
421 p += 5;
423 nameptr = p;
425 #if 0
427 for (d = subnetlist; d; d = d->next)
429 struct work_record *work;
431 for (work = d->workgrouplist; work; work = work->next)
433 struct server_record *s;
435 if (!strequal(work->work_group, work_name)) continue;
437 for (s = work->serverlist; s; s = s->next)
439 BOOL found = False;
440 char *n;
442 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
444 for (n = nameptr; n < p; n = skip_string(n, 1))
446 if (strequal(n, s->serv.name)) found = True;
449 if (found) continue; /* exclude names already added */
451 /* workgroup request: include all backup browsers in the list */
452 /* domain request: include all domain members in the list */
454 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
455 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
457 DEBUG(4, ("%s ", s->serv.name));
459 count++;
460 strcpy(p,s->serv.name);
461 strupper(p);
462 p = skip_string(p,1);
468 #endif
470 count++;
471 strcpy(p,myname);
472 strupper(p);
473 p = skip_string(p,1);
475 if (count == 0)
477 DEBUG(4, ("none\n"));
479 else
481 DEBUG(4, (" - count %d\n", count));
484 CVAL(countptr, 0) = count;
487 int len = PTR_DIFF(p, outbuf);
488 debug_browse_data(outbuf, len);
490 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
491 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
495 /*******************************************************************
496 process a send backup list request
498 A client sends a backup list request to ask for a list of servers on
499 the net that maintain server lists for a domain. A server is then
500 chosen from this list to send NetServerEnum commands to to list
501 available servers.
503 Currently samba only sends back one name in the backup list, its
504 own. For larger nets we'll have to add backups and send "become
505 backup" requests occasionally.
506 ******************************************************************/
507 static void process_send_backup_list(struct packet_struct *p,char *buf)
509 struct dgram_packet *dgram = &p->packet.dgram;
510 struct in_addr ip = dgram->header.source_ip;
511 struct subnet_record *d;
512 struct work_record *work;
514 int token = CVAL(buf,0); /* sender's key index for the workgroup */
515 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
516 int name_type = dgram->dest_name.name_type;
518 if (same_context(dgram)) return;
520 if (name_type != 0x1b && name_type != 0x1d) {
521 DEBUG(0,("backup request to wrong type %d from %s\n",
522 name_type,inet_ntoa(ip)));
523 return;
526 for (d = subnetlist; d; d = d->next)
528 for (work = d->workgrouplist; work; work = work->next)
530 if (strequal(work->work_group, dgram->dest_name.name))
532 DEBUG(2,("sending backup list to %s %s id=%x\n",
533 namestr(&dgram->dest_name),inet_ntoa(ip),info));
535 send_backup_list(work->work_group,&dgram->source_name,
536 token,info,name_type,ip);
537 return;
544 /*******************************************************************
545 process a reset browser state
547 diagnostic packet:
548 0x1 - stop being a master browser and become a backup browser.
549 0x2 - discard browse lists, stop being a master browser, try again.
550 0x4 - stop being a master browser forever. no way. ain't gonna.
552 ******************************************************************/
553 static void process_reset_browser(struct packet_struct *p,char *buf)
555 struct dgram_packet *dgram = &p->packet.dgram;
556 int state = CVAL(buf,0);
558 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
559 namestr(&dgram->dest_name), state));
561 /* stop being a master but still deal with being a backup browser */
562 if (state & 0x1)
564 struct subnet_record *d;
565 for (d = subnetlist; d; d = d->next)
567 struct work_record *work;
568 for (work = d->workgrouplist; work; work = work->next)
570 if (AM_MASTER(work))
572 become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
578 /* XXXX documentation inconsistency: the above description does not
579 exactly tally with what is implemented for state & 0x2
582 /* totally delete all servers and start afresh */
583 if (state & 0x2)
585 struct subnet_record *d;
586 for (d = subnetlist; d; d = d->next)
588 struct work_record *work;
589 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
591 add_my_subnets(lp_workgroup());
594 /* stop browsing altogether. i don't think this is a good idea! */
595 if (state & 0x4)
597 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
601 /*******************************************************************
602 process a announcement request
604 clients send these when they want everyone to send an announcement
605 immediately. This can cause quite a storm of packets!
606 ******************************************************************/
607 static void process_announce_request(struct packet_struct *p,char *buf)
609 struct dgram_packet *dgram = &p->packet.dgram;
610 struct work_record *work;
611 struct in_addr ip = dgram->header.source_ip;
612 struct subnet_record *d = find_subnet(ip);
613 int token = CVAL(buf,0);
614 char *name = buf+1;
616 name[15] = 0;
618 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
619 name,namestr(&dgram->dest_name), token));
621 if (strequal(dgram->source_name.name,myname)) return;
623 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
624 this workgroup before announcing, particularly as we only
625 respond on local interfaces anyway.
627 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
630 if (!d) return;
632 for (work = d->workgrouplist; work; work = work->next)
634 /* XXXX BUG: the destination name type should also be checked,
635 not just the name. e.g if the name is WORKGROUP(0x1d) then
636 we should only respond if we own that name */
638 if (strequal(dgram->dest_name.name,work->work_group))
640 work->needannounce = True;
647 /****************************************************************************
648 process a browse frame
649 ****************************************************************************/
650 void process_browse_packet(struct packet_struct *p,char *buf,int len)
652 int command = CVAL(buf,0);
653 switch (command)
655 case ANN_HostAnnouncement:
656 case ANN_DomainAnnouncement:
657 case ANN_LocalMasterAnnouncement:
659 debug_browse_data(buf, len);
660 process_announce(p,command,buf+1);
661 break;
664 case ANN_AnnouncementRequest:
666 process_announce_request(p,buf+1);
667 break;
670 case ANN_Election:
672 process_election(p,buf+1);
673 break;
676 case ANN_GetBackupListReq:
678 debug_browse_data(buf, len);
679 process_send_backup_list(p,buf+1);
680 break;
683 case ANN_GetBackupListResp:
685 debug_browse_data(buf, len);
686 process_rcv_backup_list(p, buf+1);
687 break;
690 case ANN_ResetBrowserState:
692 process_reset_browser(p, buf+1);
693 break;
696 case ANN_MasterAnnouncement:
698 process_master_announce(p,buf+1);
699 break;
702 default:
704 struct dgram_packet *dgram = &p->packet.dgram;
705 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
706 command, namestr(&dgram->source_name),
707 inet_ntoa(p->ip), namestr(&dgram->dest_name)));