some cleanups in the clientutil.c code.
[Samba.git] / source / namework.c
blob2de4a3016f7bc1e4924689b894dcc1fbb32ec2d9
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,
377 return;
382 #endif
387 /****************************************************************************
388 send a backup list response.
389 **************************************************************************/
390 static void send_backup_list(char *work_name, struct nmb_name *src_name,
391 int token, uint32 info,
392 int name_type, struct in_addr ip)
394 char outbuf[1024];
395 char *p, *countptr, *nameptr;
396 int count = 0;
397 char *theirname = src_name->name;
399 DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
400 work_name, inet_ntoa(ip),
401 myname,0x0,theirname,0x0));
403 if (name_type == 0x1d)
405 DEBUG(4,("master browsers: "));
407 else if (name_type == 0x1b)
409 DEBUG(4,("domain controllers: "));
411 else
413 DEBUG(0,("backup request for unknown type %0x\n", name_type));
414 return;
417 bzero(outbuf,sizeof(outbuf));
418 p = outbuf;
420 CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
422 p++;
423 countptr = p;
425 SIVAL(p,1,info); /* the sender's unique info */
427 p += 5;
429 nameptr = p;
431 #if 0
433 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
435 struct work_record *work;
437 for (work = d->workgrouplist; work; work = work->next)
439 struct server_record *s;
441 if (!strequal(work->work_group, work_name)) continue;
443 for (s = work->serverlist; s; s = s->next)
445 BOOL found = False;
446 char *n;
448 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
450 for (n = nameptr; n < p; n = skip_string(n, 1))
452 if (strequal(n, s->serv.name)) found = True;
455 if (found) continue; /* exclude names already added */
457 /* workgroup request: include all backup browsers in the list */
458 /* domain request: include all domain members in the list */
460 if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
461 (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
463 DEBUG(4, ("%s ", s->serv.name));
465 count++;
466 strcpy(p,s->serv.name);
467 strupper(p);
468 p = skip_string(p,1);
474 #endif
476 count++;
477 strcpy(p,myname);
478 strupper(p);
479 p = skip_string(p,1);
481 if (count == 0)
483 DEBUG(4, ("none\n"));
485 else
487 DEBUG(4, (" - count %d\n", count));
490 CVAL(countptr, 0) = count;
493 int len = PTR_DIFF(p, outbuf);
494 debug_browse_data(outbuf, len);
496 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
497 outbuf,PTR_DIFF(p,outbuf),
498 myname,theirname,0x0,0x0,ip,*iface_ip(ip));
502 /*******************************************************************
503 process a send backup list request
505 A client sends a backup list request to ask for a list of servers on
506 the net that maintain server lists for a domain. A server is then
507 chosen from this list to send NetServerEnum commands to to list
508 available servers.
510 Currently samba only sends back one name in the backup list, its
511 own. For larger nets we'll have to add backups and send "become
512 backup" requests occasionally.
513 ******************************************************************/
514 static void process_send_backup_list(struct packet_struct *p,char *buf)
516 struct dgram_packet *dgram = &p->packet.dgram;
517 struct in_addr ip = dgram->header.source_ip;
518 struct subnet_record *d;
519 struct work_record *work;
521 int token = CVAL(buf,0); /* sender's key index for the workgroup */
522 uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
523 int name_type = dgram->dest_name.name_type;
525 if (same_context(dgram)) return;
527 if (name_type != 0x1b && name_type != 0x1d) {
528 DEBUG(0,("backup request to wrong type %d from %s\n",
529 name_type,inet_ntoa(ip)));
530 return;
533 for (d = subnetlist; d; d = d->next)
535 for (work = d->workgrouplist; work; work = work->next)
537 if (strequal(work->work_group, dgram->dest_name.name))
539 DEBUG(2,("sending backup list to %s %s id=%x\n",
540 namestr(&dgram->dest_name),inet_ntoa(ip),info));
542 send_backup_list(work->work_group,&dgram->source_name,
543 token,info,name_type,ip);
544 return;
551 /*******************************************************************
552 process a reset browser state
554 diagnostic packet:
555 0x1 - stop being a master browser and become a backup browser.
556 0x2 - discard browse lists, stop being a master browser, try again.
557 0x4 - stop being a master browser forever. no way. ain't gonna.
559 ******************************************************************/
560 static void process_reset_browser(struct packet_struct *p,char *buf)
562 struct dgram_packet *dgram = &p->packet.dgram;
563 int state = CVAL(buf,0);
565 DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
566 namestr(&dgram->dest_name), state));
568 /* stop being a master but still deal with being a backup browser */
569 if (state & 0x1)
571 struct subnet_record *d;
572 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
574 struct work_record *work;
575 for (work = d->workgrouplist; work; work = work->next)
577 if (AM_MASTER(work))
579 unbecome_local_master(d,work,SV_TYPE_MASTER_BROWSER);
585 /* XXXX documentation inconsistency: the above description does not
586 exactly tally with what is implemented for state & 0x2
589 /* totally delete all servers and start afresh */
590 if (state & 0x2)
592 struct subnet_record *d;
593 for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
595 struct work_record *work;
596 for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
598 add_my_subnets(myworkgroup);
601 /* stop browsing altogether. i don't think this is a good idea! */
602 if (state & 0x4)
604 DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
608 /*******************************************************************
609 process a announcement request
611 clients send these when they want everyone to send an announcement
612 immediately. This can cause quite a storm of packets!
613 ******************************************************************/
614 static void process_announce_request(struct packet_struct *p,char *buf)
616 struct dgram_packet *dgram = &p->packet.dgram;
617 struct work_record *work;
618 struct in_addr ip = dgram->header.source_ip;
619 struct subnet_record *d = find_subnet(ip); /* Explicitly NO WINS */
620 int token = CVAL(buf,0);
621 char *name = buf+1;
623 name[15] = 0;
625 DEBUG(3,("process_announce_request: Announce request from %s to %s token=0x%X\n",
626 name,namestr(&dgram->dest_name), token));
628 if (is_myname(dgram->source_name.name)) return;
630 /* XXXX BUG or FEATURE?: need to ensure that we are a member of
631 this workgroup before announcing, particularly as we only
632 respond on local interfaces anyway.
634 if (strequal(dgram->dest_name, myworkgroup) return; ???
637 if (!d)
639 DEBUG(3,("process_announce_request: No local interface to announce to %s\n",
640 name));
641 return;
644 for (work = d->workgrouplist; work; work = work->next)
646 /* XXXX BUG: the destination name type should also be checked,
647 not just the name. e.g if the name is WORKGROUP(0x1d) then
648 we should only respond if we own that name */
650 if (strequal(dgram->dest_name.name,work->work_group))
652 work->needannounce = True;
659 /****************************************************************************
660 process a browse frame
661 ****************************************************************************/
662 void process_browse_packet(struct packet_struct *p,char *buf,int len)
664 int command = CVAL(buf,0);
665 switch (command)
667 case ANN_HostAnnouncement:
668 case ANN_DomainAnnouncement:
669 case ANN_LocalMasterAnnouncement:
671 debug_browse_data(buf, len);
672 process_localnet_announce(p,command,buf+1);
673 break;
676 case ANN_AnnouncementRequest:
678 process_announce_request(p,buf+1);
679 break;
682 case ANN_Election:
684 process_election(p,buf+1);
685 break;
688 case ANN_GetBackupListReq:
690 debug_browse_data(buf, len);
691 process_send_backup_list(p,buf+1);
692 break;
695 case ANN_GetBackupListResp:
697 debug_browse_data(buf, len);
698 process_rcv_backup_list(p, buf+1);
699 break;
702 case ANN_ResetBrowserState:
704 process_reset_browser(p, buf+1);
705 break;
708 case ANN_MasterAnnouncement:
710 process_master_announce(p,buf+1);
711 break;
714 default:
716 struct dgram_packet *dgram = &p->packet.dgram;
717 DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
718 command, namestr(&dgram->source_name),
719 inet_ntoa(p->ip), namestr(&dgram->dest_name)));