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 DEBUGLEVEL
;
35 extern time_t StartupTime
;
36 extern pstring myname
;
38 extern struct in_addr bcast_ip
;
40 /* this is our browse master/backup cache database */
41 struct browse_cache_record
*browserlist
= NULL
;
43 /* this is our domain/workgroup/server database */
44 struct domain_record
*domainlist
= NULL
;
46 static BOOL updatedlists
= True
;
49 int workgroup_count
= 0; /* unique index key: one for each workgroup */
51 /* what server type are we currently */
53 #define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
54 SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \
55 SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
57 /* here are my election parameters */
58 #define MSBROWSE "\001\002__MSBROWSE__\002"
61 /****************************************************************************
62 add a workgroup into the domain list
63 **************************************************************************/
64 static void add_workgroup(struct work_record
*work
, struct domain_record
*d
)
66 struct work_record
*w2
;
68 if (!work
|| !d
) return;
70 if (!d
->workgrouplist
)
72 d
->workgrouplist
= work
;
78 for (w2
= d
->workgrouplist
; w2
->next
; w2
= w2
->next
);
86 /****************************************************************************
87 create a blank workgroup
88 **************************************************************************/
89 static struct work_record
*make_workgroup(char *name
)
91 struct work_record
*work
;
92 struct domain_record
*d
;
95 if (!name
|| !name
[0]) return NULL
;
97 work
= (struct work_record
*)malloc(sizeof(*work
));
98 if (!work
) return(NULL
);
100 StrnCpy(work
->work_group
,name
,sizeof(work
->work_group
)-1);
101 work
->serverlist
= NULL
;
103 work
->ServerType
= DFLT_SERVER_TYPE
;
104 work
->RunningElection
= False
;
105 work
->ElectionCount
= 0;
106 work
->needelection
= False
;
107 work
->needannounce
= True
;
109 /* make sure all token representations of workgroups are unique */
111 for (d
= domainlist
; d
&& t
== -1; d
= d
->next
)
113 struct work_record
*w
;
114 for (w
= d
->workgrouplist
; w
&& t
== -1; w
= w
->next
)
116 if (strequal(w
->work_group
, work
->work_group
)) t
= w
->token
;
122 work
->token
= ++workgroup_count
;
130 /* WfWg uses 01040b01 */
131 /* Win95 uses 01041501 */
132 /* NTAS uses ???????? */
133 work
->ElectionCriterion
= (MAINTAIN_LIST
<<1)|(ELECTION_VERSION
<<8);
134 work
->ElectionCriterion
|= (lp_os_level() << 24);
135 if (lp_domain_master()) {
136 work
->ElectionCriterion
|= 0x80;
143 /*******************************************************************
144 expire old servers in the serverlist
145 time of -1 indicates everybody dies
146 ******************************************************************/
147 static void remove_old_servers(struct work_record
*work
, time_t t
)
149 struct server_record
*s
;
150 struct server_record
*nexts
;
152 /* expire old entries in the serverlist */
153 for (s
= work
->serverlist
; s
; s
= nexts
)
155 if (t
== -1 || (s
->death_time
&& s
->death_time
< t
))
157 DEBUG(3,("Removing dead server %s\n",s
->serv
.name
));
161 if (s
->prev
) s
->prev
->next
= s
->next
;
162 if (s
->next
) s
->next
->prev
= s
->prev
;
164 if (work
->serverlist
== s
)
165 work
->serverlist
= s
->next
;
177 /*******************************************************************
179 ******************************************************************/
180 struct work_record
*remove_workgroup(struct domain_record
*d
,
181 struct work_record
*work
)
183 struct work_record
*ret_work
= NULL
;
185 if (!d
|| !work
) return NULL
;
187 DEBUG(3,("Removing old workgroup %s\n", work
->work_group
));
189 remove_old_servers(work
, -1);
191 ret_work
= work
->next
;
193 if (work
->prev
) work
->prev
->next
= work
->next
;
194 if (work
->next
) work
->next
->prev
= work
->prev
;
196 if (d
->workgrouplist
== work
) d
->workgrouplist
= work
->next
;
204 /****************************************************************************
205 add a domain into the list
206 **************************************************************************/
207 static void add_domain(struct domain_record
*d
)
209 struct domain_record
*d2
;
219 for (d2
= domainlist
; d2
->next
; d2
= d2
->next
);
226 /***************************************************************************
227 add a browser into the list
228 **************************************************************************/
229 static void add_browse_cache(struct browse_cache_record
*b
)
231 struct browse_cache_record
*b2
;
241 for (b2
= browserlist
; b2
->next
; b2
= b2
->next
) ;
249 /***************************************************************************
250 add a server into the list
251 **************************************************************************/
252 static void add_server(struct work_record
*work
,struct server_record
*s
)
254 struct server_record
*s2
;
256 if (!work
->serverlist
) {
257 work
->serverlist
= s
;
263 for (s2
= work
->serverlist
; s2
->next
; s2
= s2
->next
) ;
271 /*******************************************************************
272 remove old browse entries
273 ******************************************************************/
274 void expire_browse_cache(time_t t
)
276 struct browse_cache_record
*b
;
277 struct browse_cache_record
*nextb
;
279 /* expire old entries in the serverlist */
280 for (b
= browserlist
; b
; b
= nextb
)
282 if (b
->synced
&& b
->sync_time
< t
)
284 DEBUG(3,("Removing dead cached browser %s\n",b
->name
));
287 if (b
->prev
) b
->prev
->next
= b
->next
;
288 if (b
->next
) b
->next
->prev
= b
->prev
;
290 if (browserlist
== b
) browserlist
= b
->next
;
302 /****************************************************************************
303 find a workgroup in the workgrouplist
304 only create it if the domain allows it, or the parameter 'add' insists
305 that it get created/added anyway. this allows us to force entries in
306 lmhosts file to be added.
307 **************************************************************************/
308 struct work_record
*find_workgroupstruct(struct domain_record
*d
, fstring name
, BOOL add
)
310 struct work_record
*ret
, *work
;
314 DEBUG(4, ("workgroup search for %s: ", name
));
316 if (strequal(name
, "*"))
318 DEBUG(2,("add any workgroups: initiating browser search on %s\n",
319 inet_ntoa(d
->bcast_ip
)));
320 queue_netbios_pkt_wins(ClientNMB
,NMB_QUERY
, FIND_MASTER
,
322 True
,False
, d
->bcast_ip
);
326 for (ret
= d
->workgrouplist
; ret
; ret
= ret
->next
)
328 if (!strcmp(ret
->work_group
,name
))
330 DEBUG(4, ("found\n"));
335 DEBUG(4, ("not found: creating\n"));
337 if ((work
= make_workgroup(name
)))
339 if (lp_preferred_master() &&
340 strequal(lp_workgroup(), name
) &&
341 ip_equal(d
->bcast_ip
, bcast_ip
))
343 DEBUG(3, ("preferred master startup for %s\n", work
->work_group
));
344 work
->needelection
= True
;
345 work
->ElectionCriterion
|= (1<<3);
347 if (!ip_equal(bcast_ip
, d
->bcast_ip
))
349 work
->needelection
= False
;
351 add_workgroup(work
, d
);
357 /****************************************************************************
358 find a domain in the domainlist
359 **************************************************************************/
360 struct domain_record
*find_domain(struct in_addr source_ip
)
362 struct domain_record
*d
;
364 /* search through domain list for broadcast/netmask that matches
365 the source ip address */
367 for (d
= domainlist
; d
; d
= d
->next
)
369 if (same_net(source_ip
, d
->bcast_ip
, d
->mask_ip
))
379 /****************************************************************************
380 dump a copy of the workgroup/domain database
381 **************************************************************************/
382 void dump_workgroups(void)
384 struct domain_record
*d
;
386 for (d
= domainlist
; d
; d
= d
->next
)
388 if (d
->workgrouplist
)
390 struct work_record
*work
;
392 DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d
->bcast_ip
)));
393 DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d
->mask_ip
)));
395 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
397 DEBUG(4,("\t%s(%d)\n", work
->work_group
, work
->token
));
398 if (work
->serverlist
)
400 struct server_record
*s
;
401 for (s
= work
->serverlist
; s
; s
= s
->next
)
403 DEBUG(4,("\t\t%s %8x (%s)\n",
404 s
->serv
.name
, s
->serv
.type
, s
->serv
.comment
));
412 /****************************************************************************
413 create a domain entry
414 ****************************************************************************/
415 static struct domain_record
*make_domain(struct in_addr ip
, struct in_addr mask
)
417 struct domain_record
*d
;
418 d
= (struct domain_record
*)malloc(sizeof(*d
));
420 if (!d
) return(NULL
);
422 bzero((char *)d
,sizeof(*d
));
424 DEBUG(4, ("making domain %s ", inet_ntoa(ip
)));
425 DEBUG(4, ("%s\n", inet_ntoa(mask
)));
429 d
->workgrouplist
= NULL
;
436 /****************************************************************************
437 add a domain entry. creates a workgroup, if necessary, and adds the domain
438 to the named a workgroup.
439 ****************************************************************************/
440 struct domain_record
*add_domain_entry(struct in_addr source_ip
,
441 struct in_addr source_mask
,
442 char *name
, BOOL add
)
444 struct domain_record
*d
;
447 ip
= *interpret_addr2("255.255.255.255");
449 if (zero_ip(source_ip
)) source_ip
= bcast_ip
;
451 /* add the domain into our domain database */
452 if ((d
= find_domain(source_ip
)) ||
453 (d
= make_domain(source_ip
, source_mask
)))
455 struct work_record
*w
= find_workgroupstruct(d
, name
, add
);
457 /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
458 or register with WINS server, if it's our workgroup */
459 if (strequal(lp_workgroup(), name
))
461 extern pstring ServerComment
;
462 add_name_entry(name
,0x1e,NB_ACTIVE
|NB_GROUP
);
463 add_name_entry(name
,0x0 ,NB_ACTIVE
|NB_GROUP
);
464 add_server_entry(d
,w
,myname
,w
->ServerType
,0,ServerComment
,True
);
467 DEBUG(3,("Added domain name entry %s at %s\n", name
,inet_ntoa(ip
)));
473 /****************************************************************************
475 ****************************************************************************/
476 struct browse_cache_record
*add_browser_entry(char *name
, int type
, char *wg
,
477 time_t ttl
, struct in_addr ip
)
481 struct browse_cache_record
*b
;
483 /* search for the entry: if it's already in the cache, update that entry */
484 for (b
= browserlist
; b
; b
= b
->next
)
486 if (ip_equal(ip
,b
->ip
) && strequal(b
->group
, wg
)) break;
491 /* entries get left in the cache for a while. this stops sync'ing too
492 often if the network is large */
493 DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
494 b
->name
, b
->group
, inet_ntoa(b
->ip
), b
->sync_time
));
501 b
= (struct browse_cache_record
*)malloc(sizeof(*b
));
503 if (!b
) return(NULL
);
505 bzero((char *)b
,sizeof(*b
));
508 /* update the entry */
509 ttl
= time(NULL
)+ttl
;
511 StrnCpy(b
->name
,name
,sizeof(b
->name
)-1);
512 StrnCpy(b
->group
,wg
,sizeof(b
->group
)-1);
519 if (newentry
|| ttl
< b
->sync_time
) b
->sync_time
= ttl
;
526 DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
527 wg
, name
, type
, inet_ntoa(ip
),ttl
));
531 DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
532 wg
, name
, type
, inet_ntoa(ip
),ttl
));
539 /****************************************************************************
541 ****************************************************************************/
542 struct server_record
*add_server_entry(struct domain_record
*d
,
543 struct work_record
*work
,
544 char *name
,int servertype
,
545 int ttl
,char *comment
,
549 struct server_record
*s
;
556 for (s
= work
->serverlist
; s
; s
= s
->next
)
558 if (strequal(name
,s
->serv
.name
)) break;
563 DEBUG(4,("Not replacing %s\n",name
));
572 s
= (struct server_record
*)malloc(sizeof(*s
));
574 if (!s
) return(NULL
);
576 bzero((char *)s
,sizeof(*s
));
579 if (ip_equal(bcast_ip
, d
->bcast_ip
) &&
580 strequal(lp_workgroup(),work
->work_group
))
582 servertype
|= SV_TYPE_LOCAL_LIST_ONLY
;
586 servertype
&= ~SV_TYPE_LOCAL_LIST_ONLY
;
589 /* update the entry */
590 StrnCpy(s
->serv
.name
,name
,sizeof(s
->serv
.name
)-1);
591 StrnCpy(s
->serv
.comment
,comment
,sizeof(s
->serv
.comment
)-1);
592 strupper(s
->serv
.name
);
593 s
->serv
.type
= servertype
;
594 s
->death_time
= ttl
?time(NULL
)+ttl
*3:0;
596 /* for a domain entry, the comment field refers to the server name */
598 if (s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) strupper(s
->serv
.comment
);
608 DEBUG(3,("Updated "));
611 DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
612 name
,servertype
,comment
,
613 work
->work_group
,inet_ntoa(d
->bcast_ip
)));
619 /*******************************************************************
621 ******************************************************************/
622 void write_browse_list(void)
624 struct domain_record
*d
;
626 pstring fname
,fnamenew
;
629 if (!updatedlists
) return;
634 updatedlists
= False
;
637 strcpy(fname
,lp_lockdir());
638 trim_string(fname
,NULL
,"/");
640 strcat(fname
,SERVER_LIST
);
641 strcpy(fnamenew
,fname
);
642 strcat(fnamenew
,".");
644 f
= fopen(fnamenew
,"w");
648 DEBUG(4,("Can't open %s - %s\n",fnamenew
,strerror(errno
)));
652 for (d
= domainlist
; d
; d
= d
->next
)
654 struct work_record
*work
;
655 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
657 struct server_record
*s
;
658 for (s
= work
->serverlist
; s
; s
= s
->next
)
662 /* don't list domains I don't have a master for */
663 if ((s
->serv
.type
& SV_TYPE_DOMAIN_ENUM
) &&
669 /* output server details, plus what workgroup/domain
670 they're in. without the domain information, the
671 combined list of all servers in all workgroups gets
672 sent to anyone asking about any workgroup! */
674 sprintf(tmp
, "\"%s\"", s
->serv
.name
);
675 fprintf(f
, "%-25s ", tmp
);
676 fprintf(f
, "%08x ", s
->serv
.type
);
677 sprintf(tmp
, "\"%s\" ", s
->serv
.comment
);
678 fprintf(f
, "%-30s", tmp
);
679 fprintf(f
, "\"%s\"\n", work
->work_group
);
686 chmod(fnamenew
,0644);
687 rename(fnamenew
,fname
);
688 DEBUG(3,("Wrote browse list %s\n",fname
));
692 /*******************************************************************
693 expire old servers in the serverlist
694 ******************************************************************/
695 void expire_servers(time_t t
)
697 struct domain_record
*d
;
699 for (d
= domainlist
; d
; d
= d
->next
)
701 struct work_record
*work
;
703 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
705 remove_old_servers(work
, t
);