1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-12 09:18:10 +03:00
samba-mirror/source3/nmbd/nmbd_workgroupdb.c
Jeremy Allison acf9d61421 r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
functions so we can funnel through some well known functions. Should help greatly with
malloc checking.
HEAD patch to follow.
Jeremy.
(This used to be commit 620f2e608f)
2007-10-10 10:53:32 -05:00

333 lines
11 KiB
C

/*
Unix SMB/CIFS implementation.
NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998
Copyright (C) Jeremy Allison 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
extern int ClientNMB;
extern uint16 samba_nb_type;
int workgroup_count = 0; /* unique index key: one for each workgroup */
/****************************************************************************
Add a workgroup into the list.
**************************************************************************/
static void add_workgroup(struct subnet_record *subrec, struct work_record *work)
{
work->subnet = subrec;
DLIST_ADD(subrec->workgrouplist, work);
subrec->work_changed = True;
}
/****************************************************************************
Copy name to unstring. Used by create_workgroup() and find_workgroup_on_subnet().
**************************************************************************/
static void name_to_unstring(unstring unname, const char *name)
{
nstring nname;
errno = 0;
push_ascii_nstring(nname, name);
if (errno == E2BIG) {
unstring tname;
pull_ascii_nstring(tname, sizeof(tname), nname);
unstrcpy(unname, tname);
DEBUG(0,("name_to_nstring: workgroup name %s is too long. Truncating to %s\n",
name, tname));
} else {
unstrcpy(unname, name);
}
}
/****************************************************************************
Create an empty workgroup.
**************************************************************************/
static struct work_record *create_workgroup(const char *name, int ttl)
{
struct work_record *work;
struct subnet_record *subrec;
int t = -1;
if((work = SMB_MALLOC_P(struct work_record)) == NULL) {
DEBUG(0,("create_workgroup: malloc fail !\n"));
return NULL;
}
memset((char *)work, '\0', sizeof(*work));
name_to_unstring(work->work_group, name);
work->serverlist = NULL;
work->RunningElection = False;
work->ElectionCount = 0;
work->announce_interval = 0;
work->needelection = False;
work->needannounce = True;
work->lastannounce_time = time(NULL);
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
work->dom_state = DOMAIN_NONE;
work->log_state = LOGON_NONE;
work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
/* Make sure all token representations of workgroups are unique. */
for (subrec = FIRST_SUBNET; subrec && (t == -1); subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
struct work_record *w;
for (w = subrec->workgrouplist; w && t == -1; w = w->next) {
if (strequal(w->work_group, work->work_group))
t = w->token;
}
}
if (t == -1)
work->token = ++workgroup_count;
else
work->token = t;
/* No known local master browser as yet. */
*work->local_master_browser_name = '\0';
/* No known domain master browser as yet. */
*work->dmb_name.name = '\0';
zero_ip(&work->dmb_addr);
/* WfWg uses 01040b01 */
/* Win95 uses 01041501 */
/* NTAS uses ???????? */
work->ElectionCriterion = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8);
work->ElectionCriterion |= (lp_os_level() << 24);
if (lp_domain_master())
work->ElectionCriterion |= 0x80;
return work;
}
/*******************************************************************
Remove a workgroup.
******************************************************************/
static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec,
struct work_record *work)
{
struct work_record *ret_work = NULL;
DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
ret_work = work->next;
remove_all_servers(work);
if (!work->serverlist) {
if (work->prev)
work->prev->next = work->next;
if (work->next)
work->next->prev = work->prev;
if (subrec->workgrouplist == work)
subrec->workgrouplist = work->next;
ZERO_STRUCTP(work);
SAFE_FREE(work);
}
subrec->work_changed = True;
return ret_work;
}
/****************************************************************************
Find a workgroup in the workgroup list of a subnet.
**************************************************************************/
struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec,
const char *name)
{
struct work_record *ret;
unstring un_name;
DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
name, subrec->subnet_name));
name_to_unstring(un_name, name);
for (ret = subrec->workgrouplist; ret; ret = ret->next) {
if (strequal(ret->work_group,un_name)) {
DEBUGADD(4, ("found.\n"));
return(ret);
}
}
DEBUGADD(4, ("not found.\n"));
return NULL;
}
/****************************************************************************
Create a workgroup in the workgroup list of the subnet.
**************************************************************************/
struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
const char *name, int ttl)
{
struct work_record *work = NULL;
DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
name, subrec->subnet_name));
if ((work = create_workgroup(name, ttl))) {
add_workgroup(subrec, work);
subrec->work_changed = True;
return(work);
}
return NULL;
}
/****************************************************************************
Update a workgroup ttl.
**************************************************************************/
void update_workgroup_ttl(struct work_record *work, int ttl)
{
if(work->death_time != PERMANENT_TTL)
work->death_time = time(NULL)+(ttl*3);
work->subnet->work_changed = True;
}
/****************************************************************************
Fail function called if we cannot register the WORKGROUP<0> and
WORKGROUP<1e> names on the net.
**************************************************************************/
static void fail_register(struct subnet_record *subrec, struct response_record *rrec,
struct nmb_name *nmbname)
{
DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
nmb_namestr(nmbname), subrec->subnet_name));
}
/****************************************************************************
If the workgroup is our primary workgroup, add the required names to it.
**************************************************************************/
void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work)
{
int i;
if(!strequal(lp_workgroup(), work->work_group))
return;
/* If this is a broadcast subnet then start elections on it if we are so configured. */
if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
(subrec != wins_server_subnet) && lp_preferred_master() && lp_local_master()) {
DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
work->needelection = True;
work->ElectionCriterion |= (1<<3);
}
/* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
register_name(subrec,lp_workgroup(),0x0,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
register_name(subrec,lp_workgroup(),0x1e,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
for( i = 0; my_netbios_names(i); i++) {
const char *name = my_netbios_names(i);
int stype = lp_default_server_announce() | (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0 );
if(!strequal(global_myname(), name))
stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY, PERMANENT_TTL,
string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
on subnet %s\n", name, subrec->subnet_name));
}
}
/****************************************************************************
Dump a copy of the workgroup database into the log file.
**************************************************************************/
void dump_workgroups(BOOL force_write)
{
struct subnet_record *subrec;
int debuglevel = force_write ? 0 : 4;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
if (subrec->workgrouplist) {
struct work_record *work;
if( DEBUGLVL( debuglevel ) ) {
dbgtext( "dump_workgroups()\n " );
dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name );
dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) );
}
for (work = subrec->workgrouplist; work; work = work->next) {
DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n", work->work_group,
work->token, *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ) );
if (work->serverlist) {
struct server_record *servrec;
for (servrec = work->serverlist; servrec; servrec = servrec->next) {
DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n",
servrec->serv.name,
servrec->serv.type,
servrec->serv.comment ) );
}
}
}
}
}
}
/****************************************************************************
Expire any dead servers on all workgroups. If the workgroup has expired
remove it.
**************************************************************************/
void expire_workgroups_and_servers(time_t t)
{
struct subnet_record *subrec;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
struct work_record *work;
struct work_record *nextwork;
for (work = subrec->workgrouplist; work; work = nextwork) {
nextwork = work->next;
expire_servers(work, t);
if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) &&
((t == -1) || (work->death_time < t))) {
DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
work->work_group));
remove_workgroup_from_subnet(subrec, work);
}
}
}
}