missed some bits. added some more on profiles - e.g windows 95 description
[Samba.git] / source / namework.c
blob20c1050597e2161bc5c462cceaa75421940d622f
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(False,BROWSE_MAILSLOT,ClientDGRAM,
83 outbuf,PTR_DIFF(p,outbuf),
84 myname,name,0x20,0x1d,ip,*iface_ip(ip));
88 /****************************************************************************
89 tell a server to become a backup browser
90 **************************************************************************/
91 void tell_become_backup(void)
93 /* XXXX note: this function is currently unsuitable for use, as it
94 does not properly check that a server is in a fit state to become
95 a backup browser before asking it to be one.
98 struct subnet_record *d;
99 for (d = subnetlist; d; d = d->next)
101 struct work_record *work;
102 for (work = d->workgrouplist; work; work = work->next)
104 struct server_record *s;
105 int num_servers = 0;
106 int num_backups = 0;
108 for (s = work->serverlist; s; s = s->next)
110 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
112 num_servers++;
114 if (strequal(myname, s->serv.name)) continue;
116 if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
117 num_backups++;
118 continue;
121 if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
123 if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
125 DEBUG(3,("num servers: %d num backups: %d\n",
126 num_servers, num_backups));
128 /* make first server a backup server. thereafter make every
129 tenth server a backup server */
130 if (num_backups != 0 && (num_servers+9) / num_backups > 10)
132 continue;
135 DEBUG(2,("sending become backup to %s %s for %s\n",
136 s->serv.name, inet_ntoa(d->bcast_ip),
137 work->work_group));
139 /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
140 do_announce_request(s->serv.name, work->work_group,
141 ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
148 /*******************************************************************
149 same context: scope. should check name_type as well, and makes sure
150 we don't process messages from ourselves
151 ******************************************************************/
152 BOOL same_context(struct dgram_packet *dgram)
154 if (!strequal(dgram->dest_name .scope,scope )) return(True);
155 if ( strequal(dgram->source_name.name ,myname)) return(True);
157 return(False);
161 /*******************************************************************
162 process a domain announcement frame
164 Announce frames come in 3 types. Servers send host announcements
165 (command=1) to let the master browswer know they are
166 available. Master browsers send local master announcements
167 (command=15) to let other masters and backups that they are the
168 master. They also send domain announcements (command=12) to register
169 the domain
171 The comment field of domain announcements contains the master
172 browser name. The servertype is used by NetServerEnum to select
173 resources. We just have to pass it to smbd (via browser.dat) and let
174 the client choose using bit masks.
175 ******************************************************************/
176 static void process_announce(struct packet_struct *p,uint16 command,char *buf)
178 struct dgram_packet *dgram = &p->packet.dgram;
179 struct subnet_record *d = find_subnet(p->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(p->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 DEBUG(4,("search for workgroup: %s (add? %s)\n",
247 work_name, BOOLSTR(add)));
249 if (!(work = find_workgroupstruct(d, work_name,add)))
250 return;
252 DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
254 ttl = GET_TTL(ttl);
256 /* add them to our browse list, and update the browse.dat file */
257 add_server_entry(d,work,name,servertype,ttl,comment,True);
258 updatedlists = True;
260 #if 0
261 /* the tell become backup code is broken, no great harm is done by
262 disabling it */
263 tell_become_backup();
264 #endif
266 /* get the local_only browse list from the local master and add it
267 to ours. */
268 if (command == ANN_LocalMasterAnnouncement)
270 add_browser_entry(serv_name,dgram->dest_name.name_type,
271 work->work_group,30,p->ip,True);
275 /*******************************************************************
276 process a master announcement frame
277 ******************************************************************/
278 static void process_master_announce(struct packet_struct *p,char *buf)
280 struct dgram_packet *dgram = &p->packet.dgram;
281 struct subnet_record *d = find_subnet(p->ip);
282 char *name = buf;
283 struct work_record *work;
284 name[15] = 0;
286 DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
288 if (same_context(dgram)) return;
290 if (!d) return;
292 if (!lp_domain_master()) return;
294 for (work = d->workgrouplist; work; work = work->next)
296 if (AM_MASTER(work))
298 /* merge browse lists with them */
299 add_browser_entry(name,0x1b, work->work_group,30,p->ip,True);
304 /*******************************************************************
305 process a receive backup list request
307 we receive a list of servers, and we attempt to locate them all on
308 our local subnet, and sync browse lists with them on the workgroup
309 they are said to be in.
311 XXXX NOTE: this function is in overdrive. it should not really do
312 half of what it actually does (it should pick _one_ name from the
313 list received and sync with it at regular intervals, rather than
314 sync with them all only once!)
316 ******************************************************************/
317 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
319 struct dgram_packet *dgram = &p->packet.dgram;
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(p->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(p->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 #if 0
356 /* XXXX function needs work */
357 continue;
359 if ((d = find_subnet(back_ip)))
361 struct subnet_record *d1;
362 for (d1 = subnetlist; d1; d1 = d1->next)
364 struct work_record *work;
365 for (work = d1->workgrouplist; work; work = work->next)
367 if (work->token == 0 /* token */)
369 queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
370 work->work_group,0x1d,
371 0,0,0,NULL,NULL,
372 False,False,back_ip,back_ip);
373 return;
378 #endif
383 /****************************************************************************
384 send a backup list response.
385 **************************************************************************/
386 static void send_backup_list(char *work_name, struct nmb_name *src_name,
387 int token, uint32 info,
388 int name_type, struct in_addr ip)
390 char outbuf[1024];
391 char *p, *countptr, *nameptr;
392 int count = 0;
393 char *theirname = src_name->name;
395 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
396 work_name, inet_ntoa(ip),
397 myname,0x0,theirname,0x0));
399 if (name_type == 0x1d)
401 DEBUG(4,("master browsers: "));
403 else if (name_type == 0x1b)
405 DEBUG(4,("domain controllers: "));
407 else
409 DEBUG(0,("backup request for unknown type %0x\n", name_type));
410 return;
413 bzero(outbuf,sizeof(outbuf));
414 p = outbuf;
416 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
418 p++;
419 countptr = p;
421 SIVAL(p,1,info); /* the sender's unique info */
423 p += 5;
425 nameptr = p;
427 #if 0
429 for (d = subnetlist; d; d = d->next)
431 struct work_record *work;
433 for (work = d->workgrouplist; work; work = work->next)
435 struct server_record *s;
437 if (!strequal(work->work_group, work_name)) continue;
439 for (s = work->serverlist; s; s = s->next)
441 BOOL found = False;
442 char *n;
444 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
446 for (n = nameptr; n < p; n = skip_string(n, 1))
448 if (strequal(n, s->serv.name)) found = True;
451 if (found) continue; /* exclude names already added */
453 /* workgroup request: include all backup browsers in the list */
454 /* domain request: include all domain members in the list */
456 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
457 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
459 DEBUG(4, ("%s ", s->serv.name));
461 count++;
462 strcpy(p,s->serv.name);
463 strupper(p);
464 p = skip_string(p,1);
470 #endif
472 count++;
473 strcpy(p,myname);
474 strupper(p);
475 p = skip_string(p,1);
477 if (count == 0)
479 DEBUG(4, ("none\n"));
481 else
483 DEBUG(4, (" - count %d\n", count));
486 CVAL(countptr, 0) = count;
489 int len = PTR_DIFF(p, outbuf);
490 debug_browse_data(outbuf, len);
492 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
493 outbuf,PTR_DIFF(p,outbuf),
494 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
498 /*******************************************************************
499 process a send backup list request
501 A client sends a backup list request to ask for a list of servers on
502 the net that maintain server lists for a domain. A server is then
503 chosen from this list to send NetServerEnum commands to to list
504 available servers.
506 Currently samba only sends back one name in the backup list, its
507 own. For larger nets we'll have to add backups and send "become
508 backup" requests occasionally.
509 ******************************************************************/
510 static void process_send_backup_list(struct packet_struct *p,char *buf)
512 struct dgram_packet *dgram = &p->packet.dgram;
513 struct in_addr ip = dgram->header.source_ip;
514 struct subnet_record *d;
515 struct work_record *work;
517 int token = CVAL(buf,0); /* sender's key index for the workgroup */
518 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
519 int name_type = dgram->dest_name.name_type;
521 if (same_context(dgram)) return;
523 if (name_type != 0x1b && name_type != 0x1d) {
524 DEBUG(0,("backup request to wrong type %d from %s\n",
525 name_type,inet_ntoa(ip)));
526 return;
529 for (d = subnetlist; d; d = d->next)
531 for (work = d->workgrouplist; work; work = work->next)
533 if (strequal(work->work_group, dgram->dest_name.name))
535 DEBUG(2,("sending backup list to %s %s id=%x\n",
536 namestr(&dgram->dest_name),inet_ntoa(ip),info));
538 send_backup_list(work->work_group,&dgram->source_name,
539 token,info,name_type,ip);
540 return;
547 /*******************************************************************
548 process a reset browser state
550 diagnostic packet:
551 0x1 - stop being a master browser and become a backup browser.
552 0x2 - discard browse lists, stop being a master browser, try again.
553 0x4 - stop being a master browser forever. no way. ain't gonna.
555 ******************************************************************/
556 static void process_reset_browser(struct packet_struct *p,char *buf)
558 struct dgram_packet *dgram = &p->packet.dgram;
559 int state = CVAL(buf,0);
561 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
562 namestr(&dgram->dest_name), state));
564 /* stop being a master but still deal with being a backup browser */
565 if (state & 0x1)
567 struct subnet_record *d;
568 for (d = subnetlist; d; d = d->next)
570 struct work_record *work;
571 for (work = d->workgrouplist; work; work = work->next)
573 if (AM_MASTER(work))
575 unbecome_local_master(d,work,SV_TYPE_MASTER_BROWSER);
581 /* XXXX documentation inconsistency: the above description does not
582 exactly tally with what is implemented for state & 0x2
585 /* totally delete all servers and start afresh */
586 if (state & 0x2)
588 struct subnet_record *d;
589 for (d = subnetlist; d; d = d->next)
591 struct work_record *work;
592 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
594 add_my_subnets(lp_workgroup());
597 /* stop browsing altogether. i don't think this is a good idea! */
598 if (state & 0x4)
600 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
604 /*******************************************************************
605 process a announcement request
607 clients send these when they want everyone to send an announcement
608 immediately. This can cause quite a storm of packets!
609 ******************************************************************/
610 static void process_announce_request(struct packet_struct *p,char *buf)
612 struct dgram_packet *dgram = &p->packet.dgram;
613 struct work_record *work;
614 struct in_addr ip = dgram->header.source_ip;
615 struct subnet_record *d = find_subnet(ip);
616 int token = CVAL(buf,0);
617 char *name = buf+1;
619 name[15] = 0;
621 DEBUG(3,("Announce request from %s to %s token=0x%X\n",
622 name,namestr(&dgram->dest_name), token));
624 if (strequal(dgram->source_name.name,myname)) return;
626 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
627 this workgroup before announcing, particularly as we only
628 respond on local interfaces anyway.
630 if (strequal(dgram->dest_name, lp_workgroup()) return; ???
633 if (!d) return;
635 for (work = d->workgrouplist; work; work = work->next)
637 /* XXXX BUG: the destination name type should also be checked,
638 not just the name. e.g if the name is WORKGROUP(0x1d) then
639 we should only respond if we own that name */
641 if (strequal(dgram->dest_name.name,work->work_group))
643 work->needannounce = True;
650 /****************************************************************************
651 process a browse frame
652 ****************************************************************************/
653 void process_browse_packet(struct packet_struct *p,char *buf,int len)
655 int command = CVAL(buf,0);
656 switch (command)
658 case ANN_HostAnnouncement:
659 case ANN_DomainAnnouncement:
660 case ANN_LocalMasterAnnouncement:
662 debug_browse_data(buf, len);
663 process_announce(p,command,buf+1);
664 break;
667 case ANN_AnnouncementRequest:
669 process_announce_request(p,buf+1);
670 break;
673 case ANN_Election:
675 process_election(p,buf+1);
676 break;
679 case ANN_GetBackupListReq:
681 debug_browse_data(buf, len);
682 process_send_backup_list(p,buf+1);
683 break;
686 case ANN_GetBackupListResp:
688 debug_browse_data(buf, len);
689 process_rcv_backup_list(p, buf+1);
690 break;
693 case ANN_ResetBrowserState:
695 process_reset_browser(p, buf+1);
696 break;
699 case ANN_MasterAnnouncement:
701 process_master_announce(p,buf+1);
702 break;
705 default:
707 struct dgram_packet *dgram = &p->packet.dgram;
708 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
709 command, namestr(&dgram->source_name),
710 inet_ntoa(p->ip), namestr(&dgram->dest_name)));