From Jacco, unchanged. Destined for Samba-Client-FAQ. Dan
[Samba.git] / source / namework.c
blob3e1ac220058bd20b3578d745a46fc9fa7b61c99f
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1997
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;
40 extern fstring myworkgroup;
42 extern int ClientNMB;
43 extern int ClientDGRAM;
45 extern struct in_addr ipzero;
47 extern int workgroup_count; /* total number of workgroups we know about */
49 /* this is our domain/workgroup/server database */
50 extern struct subnet_record *subnetlist;
52 extern int updatecount;
54 /* backup request types: which servers are to be included */
55 #define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
56 #define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL )
58 extern time_t StartupTime;
60 extern BOOL updatedlists;
62 /****************************************************************************
63 tell a server to become a backup browser
64 state - 0x01 become backup instead of master
65 - 0x02 remove all entries in browse list and become non-master
66 - 0x04 stop master browser service altogether. NT ignores this
67 **************************************************************************/
68 void reset_server(char *name, int state, struct in_addr ip)
70 char outbuf[20];
71 char *p;
73 bzero(outbuf,sizeof(outbuf));
74 p = outbuf;
76 CVAL(p,0) = ANN_ResetBrowserState;
77 CVAL(p,2) = state;
78 p += 2;
80 DEBUG(2,("sending reset to %s %s of state %d\n",
81 name,inet_ntoa(ip),state));
83 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
84 outbuf,PTR_DIFF(p,outbuf),
85 myname,name,0x20,0x1d,ip,*iface_ip(ip));
89 /****************************************************************************
90 tell a server to become a backup browser
91 **************************************************************************/
92 void tell_become_backup(void)
94 /* XXXX note: this function is currently unsuitable for use, as it
95 does not properly check that a server is in a fit state to become
96 a backup browser before asking it to be one.
99 struct subnet_record *d;
100 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
102 struct work_record *work;
103 for (work = d->workgrouplist; work; work = work->next)
105 struct server_record *s;
106 int num_servers = 0;
107 int num_backups = 0;
109 for (s = work->serverlist; s; s = s->next)
111 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
113 num_servers++;
115 if (is_myname(s->serv.name)) continue;
117 if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
118 num_backups++;
119 continue;
122 if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
124 if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
126 DEBUG(3,("num servers: %d num backups: %d\n",
127 num_servers, num_backups));
129 /* make first server a backup server. thereafter make every
130 tenth server a backup server */
131 if (num_backups != 0 && (num_servers+9) / num_backups > 10)
133 continue;
136 DEBUG(2,("sending become backup to %s %s for %s\n",
137 s->serv.name, inet_ntoa(d->bcast_ip),
138 work->work_group));
140 /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
141 do_announce_request(s->serv.name, work->work_group,
142 ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
149 /*******************************************************************
150 same context: scope. should check name_type as well, and makes sure
151 we don't process messages from ourselves
152 ******************************************************************/
153 BOOL same_context(struct dgram_packet *dgram)
155 if (!strequal(dgram->dest_name .scope,scope )) return(True);
156 if ( is_myname(dgram->source_name.name)) return(True);
158 return(False);
162 /*******************************************************************
163 process a domain announcement frame
165 Announce frames come in 3 types. Servers send host announcements
166 (command=1) to let the master browswer know they are
167 available. Master browsers send local master announcements
168 (command=15) to let other masters and backups that they are the
169 master. They also send domain announcements (command=12) to register
170 the domain
172 The comment field of domain announcements contains the master
173 browser name. The servertype is used by NetServerEnum to select
174 resources. We just have to pass it to smbd (via browser.dat) and let
175 the client choose using bit masks.
176 ******************************************************************/
177 static void process_localnet_announce(struct packet_struct *p,uint16 command,char *buf)
179 struct dgram_packet *dgram = &p->packet.dgram;
180 struct subnet_record *d = find_subnet(p->ip); /* Explicitly exclude WINS - local nets only */
181 int update_count = CVAL(buf,0);
183 int ttl = IVAL(buf,1)/1000;
184 char *name = buf+5;
185 int osmajor=CVAL(buf,21);
186 int osminor=CVAL(buf,22);
187 uint32 servertype = IVAL(buf,23);
188 uint32 browse_type= CVAL(buf,27);
189 uint32 browse_sig = CVAL(buf,29);
190 char *comment = buf+31;
192 struct work_record *work;
193 char *work_name;
194 char *serv_name = dgram->source_name.name;
195 BOOL add = False;
197 comment[43] = 0;
199 DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
200 DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
201 namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
202 servertype,browse_type,browse_sig,comment));
204 name[15] = 0;
206 if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
208 DEBUG(2,("Announce to nametype(0) not supported yet\n"));
209 return;
212 if (command == ANN_DomainAnnouncement &&
213 ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
214 dgram->dest_name.name_type != 0x1))
216 DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
217 command, inet_ntoa(p->ip), namestr(&dgram->dest_name)));
218 return;
221 if (!strequal(dgram->dest_name.scope,scope )) return;
223 if (command == ANN_DomainAnnouncement) {
224 /* XXXX if we are a master browser for the workgroup work_name,
225 then there is a local subnet configuration problem. only
226 we should be sending out such domain announcements, because
227 as the master browser, that is our job.
229 stop being a master browser, and force an election. this will
230 sort out the network problem. hopefully.
233 work_name = name;
234 add = True;
235 } else {
236 work_name = dgram->dest_name.name;
239 /* we need some way of finding out about new workgroups
240 that appear to be sending packets to us. The name_type checks make
241 sure we don't add host names as workgroups */
242 if (command == ANN_HostAnnouncement &&
243 (dgram->dest_name.name_type == 0x1d ||
244 dgram->dest_name.name_type == 0x1e))
245 add = True;
247 DEBUG(4,("search for workgroup: %s (add? %s)\n",
248 work_name, BOOLSTR(add)));
250 if (!(work = find_workgroupstruct(d, work_name,add)))
251 return;
253 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
255 ttl = GET_TTL(ttl);
257 /* add them to our browse list, and update the browse.dat file */
258 add_server_entry(d,work,name,servertype|SV_TYPE_LOCAL_LIST_ONLY,ttl,comment,True);
259 updatedlists = True;
261 #if 0
262 /* the tell become backup code is broken, no great harm is done by
263 disabling it */
264 tell_become_backup();
265 #endif
268 /*******************************************************************
269 process a master announcement frame
270 Domain master browsers recieve these from local masters. The Domain
271 master should then issue a sync with the local master, asking for
272 that machines local server list.
273 ******************************************************************/
274 static void process_master_announce(struct packet_struct *p,char *buf)
276 struct dgram_packet *dgram = &p->packet.dgram;
277 char *name = buf;
278 struct work_record *work;
279 name[15] = 0;
281 DEBUG(3,("process_master_announce: Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
283 if (same_context(dgram)) return;
285 if (!wins_subnet)
287 DEBUG(3,("process_master_announce: No wins subnet !\n"));
288 return;
291 if (!lp_domain_master())
293 DEBUG(3,("process_master_announce: Not configured as domain master - ignoring master announce.\n"));
294 return;
297 for (work = wins_subnet->workgrouplist; work; work = work->next)
299 if (AM_MASTER(work) || AM_DOMMST(work))
301 /* merge browse lists with them */
302 add_browser_entry(name,0x1d, work->work_group,30,wins_subnet,p->ip,True);
307 /*******************************************************************
308 process a receive backup list request
310 we receive a list of servers, and we attempt to locate them all on
311 our local subnet, and sync browse lists with them on the workgroup
312 they are said to be in.
314 XXXX NOTE: this function is in overdrive. it should not really do
315 half of what it actually does (it should pick _one_ name from the
316 list received and sync with it at regular intervals, rather than
317 sync with them all only once!)
319 ******************************************************************/
320 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
322 struct dgram_packet *dgram = &p->packet.dgram;
323 int count = CVAL(buf,0);
324 uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
325 char *buf1;
327 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
328 namestr(&dgram->dest_name), inet_ntoa(p->ip),
329 count, info));
331 if (same_context(dgram)) return;
333 if (count <= 0) return;
335 /* go through the list of servers attempting to sync browse lists */
336 for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
338 struct in_addr back_ip;
339 /* struct subnet_record *d; */
341 DEBUG(4,("Searching for backup browser %s at %s...\n",
342 buf1, inet_ntoa(p->ip)));
344 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
345 approach is to use reply_name_query functionality to find the name */
347 back_ip = *interpret_addr2(buf1);
349 if (zero_ip(back_ip))
351 DEBUG(4,("Failed to find backup browser server using DNS\n"));
352 continue;
355 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
356 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
358 #if 0
359 /* XXXX function needs work */
360 continue;
362 if ((d = find_subnet(back_ip)))
364 struct subnet_record *d1;
365 for (d1 = subnetlist; d1; d1 = d1->next)
367 struct work_record *work;
368 for (work = d1->workgrouplist; work; work = work->next)
370 if (work->token == 0 /* token */)
372 queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
373 work->work_group,0x1d,
374 0,0,0,NULL,NULL,
375 False,False,back_ip,back_ip);
376 return;
381 #endif
386 /****************************************************************************
387 send a backup list response.
388 **************************************************************************/
389 static void send_backup_list(char *work_name, struct nmb_name *src_name,
390 int token, uint32 info,
391 int name_type, struct in_addr ip)
393 char outbuf[1024];
394 char *p, *countptr, *nameptr;
395 int count = 0;
396 char *theirname = src_name->name;
398 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
399 work_name, inet_ntoa(ip),
400 myname,0x0,theirname,0x0));
402 if (name_type == 0x1d)
404 DEBUG(4,("master browsers: "));
406 else if (name_type == 0x1b)
408 DEBUG(4,("domain controllers: "));
410 else
412 DEBUG(0,("backup request for unknown type %0x\n", name_type));
413 return;
416 bzero(outbuf,sizeof(outbuf));
417 p = outbuf;
419 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
421 p++;
422 countptr = p;
424 SIVAL(p,1,info); /* the sender's unique info */
426 p += 5;
428 nameptr = p;
430 #if 0
432 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
434 struct work_record *work;
436 for (work = d->workgrouplist; work; work = work->next)
438 struct server_record *s;
440 if (!strequal(work->work_group, work_name)) continue;
442 for (s = work->serverlist; s; s = s->next)
444 BOOL found = False;
445 char *n;
447 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
449 for (n = nameptr; n < p; n = skip_string(n, 1))
451 if (strequal(n, s->serv.name)) found = True;
454 if (found) continue; /* exclude names already added */
456 /* workgroup request: include all backup browsers in the list */
457 /* domain request: include all domain members in the list */
459 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
460 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
462 DEBUG(4, ("%s ", s->serv.name));
464 count++;
465 strcpy(p,s->serv.name);
466 strupper(p);
467 p = skip_string(p,1);
473 #endif
475 count++;
476 strcpy(p,myname);
477 strupper(p);
478 p = skip_string(p,1);
480 if (count == 0)
482 DEBUG(4, ("none\n"));
484 else
486 DEBUG(4, (" - count %d\n", count));
489 CVAL(countptr, 0) = count;
492 int len = PTR_DIFF(p, outbuf);
493 debug_browse_data(outbuf, len);
495 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
496 outbuf,PTR_DIFF(p,outbuf),
497 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
501 /*******************************************************************
502 process a send backup list request
504 A client sends a backup list request to ask for a list of servers on
505 the net that maintain server lists for a domain. A server is then
506 chosen from this list to send NetServerEnum commands to to list
507 available servers.
509 Currently samba only sends back one name in the backup list, its
510 own. For larger nets we'll have to add backups and send "become
511 backup" requests occasionally.
512 ******************************************************************/
513 static void process_send_backup_list(struct packet_struct *p,char *buf)
515 struct dgram_packet *dgram = &p->packet.dgram;
516 struct in_addr ip = dgram->header.source_ip;
517 struct subnet_record *d;
518 struct work_record *work;
520 int token = CVAL(buf,0); /* sender's key index for the workgroup */
521 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
522 int name_type = dgram->dest_name.name_type;
524 if (same_context(dgram)) return;
526 if (name_type != 0x1b && name_type != 0x1d) {
527 DEBUG(0,("backup request to wrong type %d from %s\n",
528 name_type,inet_ntoa(ip)));
529 return;
532 for (d = subnetlist; d; d = d->next)
534 for (work = d->workgrouplist; work; work = work->next)
536 if (strequal(work->work_group, dgram->dest_name.name))
538 DEBUG(2,("sending backup list to %s %s id=%x\n",
539 namestr(&dgram->dest_name),inet_ntoa(ip),info));
541 send_backup_list(work->work_group,&dgram->source_name,
542 token,info,name_type,ip);
543 return;
550 /*******************************************************************
551 process a reset browser state
553 diagnostic packet:
554 0x1 - stop being a master browser and become a backup browser.
555 0x2 - discard browse lists, stop being a master browser, try again.
556 0x4 - stop being a master browser forever. no way. ain't gonna.
558 ******************************************************************/
559 static void process_reset_browser(struct packet_struct *p,char *buf)
561 struct dgram_packet *dgram = &p->packet.dgram;
562 int state = CVAL(buf,0);
564 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
565 namestr(&dgram->dest_name), state));
567 /* stop being a master but still deal with being a backup browser */
568 if (state & 0x1)
570 struct subnet_record *d;
571 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
573 struct work_record *work;
574 for (work = d->workgrouplist; work; work = work->next)
576 if (AM_MASTER(work))
578 unbecome_local_master(d,work,SV_TYPE_MASTER_BROWSER);
584 /* XXXX documentation inconsistency: the above description does not
585 exactly tally with what is implemented for state & 0x2
588 /* totally delete all servers and start afresh */
589 if (state & 0x2)
591 struct subnet_record *d;
592 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
594 struct work_record *work;
595 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
597 add_my_subnets(myworkgroup);
600 /* stop browsing altogether. i don't think this is a good idea! */
601 if (state & 0x4)
603 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
607 /*******************************************************************
608 process a announcement request
610 clients send these when they want everyone to send an announcement
611 immediately. This can cause quite a storm of packets!
612 ******************************************************************/
613 static void process_announce_request(struct packet_struct *p,char *buf)
615 struct dgram_packet *dgram = &p->packet.dgram;
616 struct work_record *work;
617 struct in_addr ip = dgram->header.source_ip;
618 struct subnet_record *d = find_subnet(ip); /* Explicitly NO WINS */
619 int token = CVAL(buf,0);
620 char *name = buf+1;
622 name[15] = 0;
624 DEBUG(3,("process_announce_request: Announce request from %s to %s token=0x%X\n",
625 name,namestr(&dgram->dest_name), token));
627 if (is_myname(dgram->source_name.name)) return;
629 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
630 this workgroup before announcing, particularly as we only
631 respond on local interfaces anyway.
633 if (strequal(dgram->dest_name, myworkgroup) return; ???
636 if (!d)
638 DEBUG(3,("process_announce_request: No local interface to announce to %s\n",
639 name));
640 return;
643 for (work = d->workgrouplist; work; work = work->next)
645 /* XXXX BUG: the destination name type should also be checked,
646 not just the name. e.g if the name is WORKGROUP(0x1d) then
647 we should only respond if we own that name */
649 if (strequal(dgram->dest_name.name,work->work_group))
651 work->needannounce = True;
658 /****************************************************************************
659 process a browse frame
660 ****************************************************************************/
661 void process_browse_packet(struct packet_struct *p,char *buf,int len)
663 int command = CVAL(buf,0);
664 switch (command)
666 case ANN_HostAnnouncement:
667 case ANN_DomainAnnouncement:
668 case ANN_LocalMasterAnnouncement:
670 debug_browse_data(buf, len);
671 process_localnet_announce(p,command,buf+1);
672 break;
675 case ANN_AnnouncementRequest:
677 process_announce_request(p,buf+1);
678 break;
681 case ANN_Election:
683 process_election(p,buf+1);
684 break;
687 case ANN_GetBackupListReq:
689 debug_browse_data(buf, len);
690 process_send_backup_list(p,buf+1);
691 break;
694 case ANN_GetBackupListResp:
696 debug_browse_data(buf, len);
697 process_rcv_backup_list(p, buf+1);
698 break;
701 case ANN_ResetBrowserState:
703 process_reset_browser(p, buf+1);
704 break;
707 case ANN_MasterAnnouncement:
709 process_master_announce(p,buf+1);
710 break;
713 default:
715 struct dgram_packet *dgram = &p->packet.dgram;
716 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
717 command, namestr(&dgram->source_name),
718 inet_ntoa(p->ip), namestr(&dgram->dest_name)));