2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1995
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.
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
33 extern int ClientDGRAM;
35 extern int DEBUGLEVEL;
37 extern time_t StartupTime;
38 extern pstring myname;
41 /* this is our browse master/backup cache database */
42 struct browse_cache_record *browserlist = NULL;
44 /* this is our domain/workgroup/server database */
45 struct domain_record *domainlist = NULL;
47 static BOOL updatedlists = True;
50 int workgroup_count = 0; /* unique index key: one for each workgroup */
52 /* what server type are we currently */
54 #define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
55 SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \
56 SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
58 /* here are my election parameters */
59 #define MSBROWSE "\001\002__MSBROWSE__\002"
62 /****************************************************************************
63 add a workgroup into the domain list
64 **************************************************************************/
65 static void add_workgroup(struct work_record *work, struct domain_record *d)
67 struct work_record *w2;
69 if (!work || !d) return;
71 if (!d->workgrouplist)
73 d->workgrouplist = work;
79 for (w2 = d->workgrouplist; w2->next; w2 = w2->next);
87 /****************************************************************************
88 create a blank workgroup
89 **************************************************************************/
90 static struct work_record *make_workgroup(char *name)
92 struct work_record *work;
93 struct domain_record *d;
96 if (!name || !name[0]) return NULL;
98 work = (struct work_record *)malloc(sizeof(*work));
99 if (!work) return(NULL);
101 StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
102 work->serverlist = NULL;
104 work->ServerType = DFLT_SERVER_TYPE;
105 work->RunningElection = False;
106 work->ElectionCount = 0;
107 work->needelection = False;
108 work->needannounce = True;
110 /* make sure all token representations of workgroups are unique */
112 for (d = domainlist; d && t == -1; d = d->next)
114 struct work_record *w;
115 for (w = d->workgrouplist; w && t == -1; w = w->next)
117 if (strequal(w->work_group, work->work_group)) t = w->token;
123 work->token = ++workgroup_count;
131 /* WfWg uses 01040b01 */
132 /* Win95 uses 01041501 */
133 /* NTAS uses ???????? */
134 work->ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8);
135 work->ElectionCriterion |= (lp_os_level() << 24);
136 if (lp_domain_master()) {
137 work->ElectionCriterion |= 0x80;
144 /*******************************************************************
145 expire old servers in the serverlist
146 time of -1 indicates everybody dies
147 ******************************************************************/
148 static void remove_old_servers(struct work_record *work, time_t t)
150 struct server_record *s;
151 struct server_record *nexts;
153 /* expire old entries in the serverlist */
154 for (s = work->serverlist; s; s = nexts)
156 if (t == -1 || (s->death_time && s->death_time < t))
158 DEBUG(3,("Removing dead server %s\n",s->serv.name));
162 if (s->prev) s->prev->next = s->next;
163 if (s->next) s->next->prev = s->prev;
165 if (work->serverlist == s)
166 work->serverlist = s->next;
178 /*******************************************************************
180 ******************************************************************/
181 struct work_record *remove_workgroup(struct domain_record *d,
182 struct work_record *work)
184 struct work_record *ret_work = NULL;
186 if (!d || !work) return NULL;
188 DEBUG(3,("Removing old workgroup %s\n", work->work_group));
190 remove_old_servers(work, -1);
192 ret_work = work->next;
194 if (work->prev) work->prev->next = work->next;
195 if (work->next) work->next->prev = work->prev;
197 if (d->workgrouplist == work) d->workgrouplist = work->next;
205 /****************************************************************************
206 add a domain into the list
207 **************************************************************************/
208 static void add_domain(struct domain_record *d)
210 struct domain_record *d2;
220 for (d2 = domainlist; d2->next; d2 = d2->next);
227 /***************************************************************************
228 add a browser into the list
229 **************************************************************************/
230 static void add_browse_cache(struct browse_cache_record *b)
232 struct browse_cache_record *b2;
242 for (b2 = browserlist; b2->next; b2 = b2->next) ;
250 /***************************************************************************
251 add a server into the list
252 **************************************************************************/
253 static void add_server(struct work_record *work,struct server_record *s)
255 struct server_record *s2;
257 if (!work->serverlist) {
258 work->serverlist = s;
264 for (s2 = work->serverlist; s2->next; s2 = s2->next) ;
272 /*******************************************************************
273 remove old browse entries
274 ******************************************************************/
275 void expire_browse_cache(time_t t)
277 struct browse_cache_record *b;
278 struct browse_cache_record *nextb;
280 /* expire old entries in the serverlist */
281 for (b = browserlist; b; b = nextb)
283 if (b->synced && b->sync_time < t)
285 DEBUG(3,("Removing dead cached browser %s\n",b->name));
288 if (b->prev) b->prev->next = b->next;
289 if (b->next) b->next->prev = b->prev;
291 if (browserlist == b) browserlist = b->next;
303 /****************************************************************************
304 find a workgroup in the workgrouplist
305 only create it if the domain allows it, or the parameter 'add' insists
306 that it get created/added anyway. this allows us to force entries in
307 lmhosts file to be added.
308 **************************************************************************/
309 struct work_record *find_workgroupstruct(struct domain_record *d,
310 fstring name, BOOL add)
312 struct work_record *ret, *work;
316 DEBUG(4, ("workgroup search for %s: ", name));
318 if (strequal(name, "*"))
320 DEBUG(2,("add any workgroups: initiating browser search on %s\n",
321 inet_ntoa(d->bcast_ip)));
322 queue_netbios_pkt_wins(ClientNMB,NMB_QUERY, FIND_MASTER,
324 True,False, d->bcast_ip);
328 for (ret = d->workgrouplist; ret; ret = ret->next) {
329 if (!strcmp(ret->work_group,name)) {
330 DEBUG(4, ("found\n"));
336 DEBUG(4, ("not found\n"));
340 DEBUG(4,("not found: creating\n"));
342 if ((work = make_workgroup(name)))
344 if (lp_preferred_master() &&
345 strequal(lp_workgroup(), name) &&
346 ismybcast(d->bcast_ip))
348 DEBUG(3, ("preferred master startup for %s\n", work->work_group));
349 work->needelection = True;
350 work->ElectionCriterion |= (1<<3);
352 if (!ismybcast(d->bcast_ip))
354 work->needelection = False;
356 add_workgroup(work, d);
362 /****************************************************************************
363 find a domain in the domainlist
364 **************************************************************************/
365 struct domain_record *find_domain(struct in_addr source_ip)
367 struct domain_record *d;
369 /* search through domain list for broadcast/netmask that matches
370 the source ip address */
372 for (d = domainlist; d; d = d->next)
374 if (same_net(source_ip, d->bcast_ip, d->mask_ip))
384 /****************************************************************************
385 dump a copy of the workgroup/domain database
386 **************************************************************************/
387 void dump_workgroups(void)
389 struct domain_record *d;
391 for (d = domainlist; d; d = d->next)
393 if (d->workgrouplist)
395 struct work_record *work;
397 DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip)));
398 DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip)));
400 for (work = d->workgrouplist; work; work = work->next)
402 DEBUG(4,("\t%s(%d)\n", work->work_group, work->token));
403 if (work->serverlist)
405 struct server_record *s;
406 for (s = work->serverlist; s; s = s->next)
408 DEBUG(4,("\t\t%s %8x (%s)\n",
409 s->serv.name, s->serv.type, s->serv.comment));
417 /****************************************************************************
418 create a domain entry
419 ****************************************************************************/
420 static struct domain_record *make_domain(struct in_addr ip, struct in_addr mask)
422 struct domain_record *d;
423 d = (struct domain_record *)malloc(sizeof(*d));
425 if (!d) return(NULL);
427 bzero((char *)d,sizeof(*d));
429 DEBUG(4, ("making domain %s ", inet_ntoa(ip)));
430 DEBUG(4, ("%s\n", inet_ntoa(mask)));
434 d->workgrouplist = NULL;
441 /****************************************************************************
442 add a domain entry. creates a workgroup, if necessary, and adds the domain
443 to the named a workgroup.
444 ****************************************************************************/
445 struct domain_record *add_domain_entry(struct in_addr source_ip,
446 struct in_addr source_mask,
447 char *name, BOOL add)
449 struct domain_record *d;
452 ip = *interpret_addr2("255.255.255.255");
454 if (zero_ip(source_ip))
455 source_ip = *iface_bcast(source_ip);
457 /* add the domain into our domain database */
458 if ((d = find_domain(source_ip)) ||
459 (d = make_domain(source_ip, source_mask)))
461 struct work_record *w = find_workgroupstruct(d, name, add);
463 /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
464 or register with WINS server, if it's our workgroup */
465 if (strequal(lp_workgroup(), name))
467 extern pstring ServerComment;
468 add_name_entry(name,0x1e,NB_ACTIVE|NB_GROUP);
469 add_name_entry(name,0x0 ,NB_ACTIVE|NB_GROUP);
470 add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True);
473 DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(ip)));
479 /****************************************************************************
481 ****************************************************************************/
482 struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
483 time_t ttl, struct in_addr ip)
487 struct browse_cache_record *b;
489 /* search for the entry: if it's already in the cache, update that entry */
490 for (b = browserlist; b; b = b->next)
492 if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
497 /* entries get left in the cache for a while. this stops sync'ing too
498 often if the network is large */
499 DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
500 b->name, b->group, inet_ntoa(b->ip), b->sync_time));
507 b = (struct browse_cache_record *)malloc(sizeof(*b));
509 if (!b) return(NULL);
511 bzero((char *)b,sizeof(*b));
514 /* update the entry */
515 ttl = time(NULL)+ttl;
517 StrnCpy(b->name ,name,sizeof(b->name )-1);
518 StrnCpy(b->group,wg ,sizeof(b->group)-1);
525 if (newentry || ttl < b->sync_time)
533 DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
534 wg, name, type, inet_ntoa(ip),ttl));
538 DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
539 wg, name, type, inet_ntoa(ip),ttl));
546 /****************************************************************************
548 ****************************************************************************/
549 struct server_record *add_server_entry(struct domain_record *d,
550 struct work_record *work,
551 char *name,int servertype,
552 int ttl,char *comment,
556 struct server_record *s;
563 for (s = work->serverlist; s; s = s->next)
565 if (strequal(name,s->serv.name)) break;
570 DEBUG(4,("Not replacing %s\n",name));
579 s = (struct server_record *)malloc(sizeof(*s));
581 if (!s) return(NULL);
583 bzero((char *)s,sizeof(*s));
586 if (ismybcast(d->bcast_ip) &&
587 strequal(lp_workgroup(),work->work_group))
589 servertype |= SV_TYPE_LOCAL_LIST_ONLY;
593 servertype &= ~SV_TYPE_LOCAL_LIST_ONLY;
596 /* update the entry */
597 StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
598 StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
599 strupper(s->serv.name);
600 s->serv.type = servertype;
601 s->death_time = ttl?time(NULL)+ttl*3:0;
603 /* for a domain entry, the comment field refers to the server name */
605 if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
615 DEBUG(3,("Updated "));
618 DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
619 name,servertype,comment,
620 work->work_group,inet_ntoa(d->bcast_ip)));
626 /*******************************************************************
628 ******************************************************************/
629 void write_browse_list(void)
631 struct domain_record *d;
633 pstring fname,fnamenew;
636 if (!updatedlists) return;
641 updatedlists = False;
644 strcpy(fname,lp_lockdir());
645 trim_string(fname,NULL,"/");
647 strcat(fname,SERVER_LIST);
648 strcpy(fnamenew,fname);
649 strcat(fnamenew,".");
651 f = fopen(fnamenew,"w");
655 DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
659 for (d = domainlist; d ; d = d->next)
661 struct work_record *work;
662 for (work = d->workgrouplist; work ; work = work->next)
664 struct server_record *s;
665 for (s = work->serverlist; s ; s = s->next)
669 /* don't list domains I don't have a master for */
670 if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) &&
676 /* output server details, plus what workgroup/domain
677 they're in. without the domain information, the
678 combined list of all servers in all workgroups gets
679 sent to anyone asking about any workgroup! */
681 sprintf(tmp, "\"%s\"", s->serv.name);
682 fprintf(f, "%-25s ", tmp);
683 fprintf(f, "%08x ", s->serv.type);
684 sprintf(tmp, "\"%s\" ", s->serv.comment);
685 fprintf(f, "%-30s", tmp);
686 fprintf(f, "\"%s\"\n", work->work_group);
693 chmod(fnamenew,0644);
694 rename(fnamenew,fname);
695 DEBUG(3,("Wrote browse list %s\n",fname));
699 /*******************************************************************
700 expire old servers in the serverlist
701 ******************************************************************/
702 void expire_servers(time_t t)
704 struct domain_record *d;
706 for (d = domainlist ; d ; d = d->next)
708 struct work_record *work;
710 for (work = d->workgrouplist; work; work = work->next)
712 remove_old_servers(work, t);