made "hide files" and "veto files" into per-service parameter sections,
[Samba.git] / source / namework.c
blobff623e69dbf94a7cc42a5795c2c0f00117233a9c
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 (strequal(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 ( strequal(dgram->source_name.name ,myname)) 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
267 #if 0 /* JRA TEST - I Think this code should not be here */
268 /* get the local_only browse list from the local master and add it
269 to ours. */
270 if (command == ANN_LocalMasterAnnouncement)
272 add_browser_entry(serv_name,dgram->dest_name.name_type,
273 work->work_group,30,p->ip,True);
275 #endif /* END JRA TEST */
278 /*******************************************************************
279 process a master announcement frame
280 Domain master browsers recieve these from local masters. The Domain
281 master should then issue a sync with the local master, asking for
282 that machines local server list.
283 ******************************************************************/
284 static void process_master_announce(struct packet_struct *p,char *buf)
286 struct dgram_packet *dgram = &p->packet.dgram;
287 char *name = buf;
288 struct work_record *work;
289 name[15] = 0;
291 DEBUG(3,("process_master_announce: Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
293 if (same_context(dgram)) return;
295 if (!wins_subnet)
297 DEBUG(3,("process_master_announce: No wins subnet !\n"));
298 return;
301 if (!lp_domain_master())
303 DEBUG(3,("process_master_announce: Not configured as domain master - ignoring master announce.\n"));
304 return;
307 for (work = wins_subnet->workgrouplist; work; work = work->next)
309 if (AM_MASTER(work) || AM_DOMMST(work))
311 /* merge browse lists with them */
312 add_browser_entry(name,0x1d, work->work_group,30,wins_subnet,p->ip,True);
317 /*******************************************************************
318 process a receive backup list request
320 we receive a list of servers, and we attempt to locate them all on
321 our local subnet, and sync browse lists with them on the workgroup
322 they are said to be in.
324 XXXX NOTE: this function is in overdrive. it should not really do
325 half of what it actually does (it should pick _one_ name from the
326 list received and sync with it at regular intervals, rather than
327 sync with them all only once!)
329 ******************************************************************/
330 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
332 struct dgram_packet *dgram = &p->packet.dgram;
333 int count = CVAL(buf,0);
334 uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
335 char *buf1;
337 DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
338 namestr(&dgram->dest_name), inet_ntoa(p->ip),
339 count, info));
341 if (same_context(dgram)) return;
343 if (count <= 0) return;
345 /* go through the list of servers attempting to sync browse lists */
346 for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
348 struct in_addr back_ip;
349 /* struct subnet_record *d; */
351 DEBUG(4,("Searching for backup browser %s at %s...\n",
352 buf1, inet_ntoa(p->ip)));
354 /* XXXX assume name is a DNS name NOT a netbios name. a more complete
355 approach is to use reply_name_query functionality to find the name */
357 back_ip = *interpret_addr2(buf1);
359 if (zero_ip(back_ip))
361 DEBUG(4,("Failed to find backup browser server using DNS\n"));
362 continue;
365 DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
366 DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
368 #if 0
369 /* XXXX function needs work */
370 continue;
372 if ((d = find_subnet(back_ip)))
374 struct subnet_record *d1;
375 for (d1 = subnetlist; d1; d1 = d1->next)
377 struct work_record *work;
378 for (work = d1->workgrouplist; work; work = work->next)
380 if (work->token == 0 /* token */)
382 queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
383 work->work_group,0x1d,
384 0,0,0,NULL,NULL,
385 False,False,back_ip,back_ip);
386 return;
391 #endif
396 /****************************************************************************
397 send a backup list response.
398 **************************************************************************/
399 static void send_backup_list(char *work_name, struct nmb_name *src_name,
400 int token, uint32 info,
401 int name_type, struct in_addr ip)
403 char outbuf[1024];
404 char *p, *countptr, *nameptr;
405 int count = 0;
406 char *theirname = src_name->name;
408 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
409 work_name, inet_ntoa(ip),
410 myname,0x0,theirname,0x0));
412 if (name_type == 0x1d)
414 DEBUG(4,("master browsers: "));
416 else if (name_type == 0x1b)
418 DEBUG(4,("domain controllers: "));
420 else
422 DEBUG(0,("backup request for unknown type %0x\n", name_type));
423 return;
426 bzero(outbuf,sizeof(outbuf));
427 p = outbuf;
429 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
431 p++;
432 countptr = p;
434 SIVAL(p,1,info); /* the sender's unique info */
436 p += 5;
438 nameptr = p;
440 #if 0
442 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
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 #endif
485 count++;
486 strcpy(p,myname);
487 strupper(p);
488 p = skip_string(p,1);
490 if (count == 0)
492 DEBUG(4, ("none\n"));
494 else
496 DEBUG(4, (" - count %d\n", count));
499 CVAL(countptr, 0) = count;
502 int len = PTR_DIFF(p, outbuf);
503 debug_browse_data(outbuf, len);
505 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
506 outbuf,PTR_DIFF(p,outbuf),
507 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
511 /*******************************************************************
512 process a send backup list request
514 A client sends a backup list request to ask for a list of servers on
515 the net that maintain server lists for a domain. A server is then
516 chosen from this list to send NetServerEnum commands to to list
517 available servers.
519 Currently samba only sends back one name in the backup list, its
520 own. For larger nets we'll have to add backups and send "become
521 backup" requests occasionally.
522 ******************************************************************/
523 static void process_send_backup_list(struct packet_struct *p,char *buf)
525 struct dgram_packet *dgram = &p->packet.dgram;
526 struct in_addr ip = dgram->header.source_ip;
527 struct subnet_record *d;
528 struct work_record *work;
530 int token = CVAL(buf,0); /* sender's key index for the workgroup */
531 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
532 int name_type = dgram->dest_name.name_type;
534 if (same_context(dgram)) return;
536 if (name_type != 0x1b && name_type != 0x1d) {
537 DEBUG(0,("backup request to wrong type %d from %s\n",
538 name_type,inet_ntoa(ip)));
539 return;
542 for (d = subnetlist; d; d = d->next)
544 for (work = d->workgrouplist; work; work = work->next)
546 if (strequal(work->work_group, dgram->dest_name.name))
548 DEBUG(2,("sending backup list to %s %s id=%x\n",
549 namestr(&dgram->dest_name),inet_ntoa(ip),info));
551 send_backup_list(work->work_group,&dgram->source_name,
552 token,info,name_type,ip);
553 return;
560 /*******************************************************************
561 process a reset browser state
563 diagnostic packet:
564 0x1 - stop being a master browser and become a backup browser.
565 0x2 - discard browse lists, stop being a master browser, try again.
566 0x4 - stop being a master browser forever. no way. ain't gonna.
568 ******************************************************************/
569 static void process_reset_browser(struct packet_struct *p,char *buf)
571 struct dgram_packet *dgram = &p->packet.dgram;
572 int state = CVAL(buf,0);
574 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
575 namestr(&dgram->dest_name), state));
577 /* stop being a master but still deal with being a backup browser */
578 if (state & 0x1)
580 struct subnet_record *d;
581 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
583 struct work_record *work;
584 for (work = d->workgrouplist; work; work = work->next)
586 if (AM_MASTER(work))
588 unbecome_local_master(d,work,SV_TYPE_MASTER_BROWSER);
594 /* XXXX documentation inconsistency: the above description does not
595 exactly tally with what is implemented for state & 0x2
598 /* totally delete all servers and start afresh */
599 if (state & 0x2)
601 struct subnet_record *d;
602 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
604 struct work_record *work;
605 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
607 add_my_subnets(myworkgroup);
610 /* stop browsing altogether. i don't think this is a good idea! */
611 if (state & 0x4)
613 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
617 /*******************************************************************
618 process a announcement request
620 clients send these when they want everyone to send an announcement
621 immediately. This can cause quite a storm of packets!
622 ******************************************************************/
623 static void process_announce_request(struct packet_struct *p,char *buf)
625 struct dgram_packet *dgram = &p->packet.dgram;
626 struct work_record *work;
627 struct in_addr ip = dgram->header.source_ip;
628 struct subnet_record *d = find_subnet(ip); /* Explicitly NO WINS */
629 int token = CVAL(buf,0);
630 char *name = buf+1;
632 name[15] = 0;
634 DEBUG(3,("process_announce_request: Announce request from %s to %s token=0x%X\n",
635 name,namestr(&dgram->dest_name), token));
637 if (strequal(dgram->source_name.name,myname)) return;
639 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
640 this workgroup before announcing, particularly as we only
641 respond on local interfaces anyway.
643 if (strequal(dgram->dest_name, myworkgroup) return; ???
646 if (!d)
648 DEBUG(3,("process_announce_request: No local interface to announce to %s\n",
649 name));
650 return;
653 for (work = d->workgrouplist; work; work = work->next)
655 /* XXXX BUG: the destination name type should also be checked,
656 not just the name. e.g if the name is WORKGROUP(0x1d) then
657 we should only respond if we own that name */
659 if (strequal(dgram->dest_name.name,work->work_group))
661 work->needannounce = True;
668 /****************************************************************************
669 process a browse frame
670 ****************************************************************************/
671 void process_browse_packet(struct packet_struct *p,char *buf,int len)
673 int command = CVAL(buf,0);
674 switch (command)
676 case ANN_HostAnnouncement:
677 case ANN_DomainAnnouncement:
678 case ANN_LocalMasterAnnouncement:
680 debug_browse_data(buf, len);
681 process_localnet_announce(p,command,buf+1);
682 break;
685 case ANN_AnnouncementRequest:
687 process_announce_request(p,buf+1);
688 break;
691 case ANN_Election:
693 process_election(p,buf+1);
694 break;
697 case ANN_GetBackupListReq:
699 debug_browse_data(buf, len);
700 process_send_backup_list(p,buf+1);
701 break;
704 case ANN_GetBackupListResp:
706 debug_browse_data(buf, len);
707 process_rcv_backup_list(p, buf+1);
708 break;
711 case ANN_ResetBrowserState:
713 process_reset_browser(p, buf+1);
714 break;
717 case ANN_MasterAnnouncement:
719 process_master_announce(p,buf+1);
720 break;
723 default:
725 struct dgram_packet *dgram = &p->packet.dgram;
726 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
727 command, namestr(&dgram->source_name),
728 inet_ntoa(p->ip), namestr(&dgram->dest_name)));