1/* 2 Unix SMB/CIFS implementation. 3 NBT netbios routines and daemon - version 2 4 Copyright (C) Andrew Tridgell 1994-1998 5 Copyright (C) Luke Kenneth Casson Leighton 1994-1998 6 Copyright (C) Jeremy Allison 1994-1998 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21*/ 22 23#include "includes.h" 24 25extern uint16 samba_nb_type; 26 27int workgroup_count = 0; /* unique index key: one for each workgroup */ 28 29/**************************************************************************** 30 Add a workgroup into the list. 31**************************************************************************/ 32 33static void add_workgroup(struct subnet_record *subrec, struct work_record *work) 34{ 35 work->subnet = subrec; 36 DLIST_ADD(subrec->workgrouplist, work); 37 subrec->work_changed = True; 38} 39 40/**************************************************************************** 41 Copy name to unstring. Used by create_workgroup() and find_workgroup_on_subnet(). 42**************************************************************************/ 43 44static void name_to_unstring(unstring unname, const char *name) 45{ 46 nstring nname; 47 48 errno = 0; 49 push_ascii_nstring(nname, name); 50 if (errno == E2BIG) { 51 unstring tname; 52 pull_ascii_nstring(tname, sizeof(tname), nname); 53 unstrcpy(unname, tname); 54 DEBUG(0,("name_to_nstring: workgroup name %s is too long. Truncating to %s\n", 55 name, tname)); 56 } else { 57 unstrcpy(unname, name); 58 } 59} 60 61/**************************************************************************** 62 Create an empty workgroup. 63**************************************************************************/ 64 65static struct work_record *create_workgroup(const char *name, int ttl) 66{ 67 struct work_record *work; 68 struct subnet_record *subrec; 69 int t = -1; 70 71 if((work = SMB_MALLOC_P(struct work_record)) == NULL) { 72 DEBUG(0,("create_workgroup: malloc fail !\n")); 73 return NULL; 74 } 75 memset((char *)work, '\0', sizeof(*work)); 76 77 name_to_unstring(work->work_group, name); 78 79 work->serverlist = NULL; 80 81 work->RunningElection = False; 82 work->ElectionCount = 0; 83 work->announce_interval = 0; 84 work->needelection = False; 85 work->needannounce = True; 86 work->lastannounce_time = time(NULL); 87 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE; 88 work->dom_state = DOMAIN_NONE; 89 work->log_state = LOGON_NONE; 90 91 work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL; 92 93 /* Make sure all token representations of workgroups are unique. */ 94 95 for (subrec = FIRST_SUBNET; subrec && (t == -1); subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) { 96 struct work_record *w; 97 for (w = subrec->workgrouplist; w && t == -1; w = w->next) { 98 if (strequal(w->work_group, work->work_group)) 99 t = w->token; 100 } 101 } 102 103 if (t == -1) 104 work->token = ++workgroup_count; 105 else 106 work->token = t; 107 108 /* No known local master browser as yet. */ 109 *work->local_master_browser_name = '\0'; 110 111 /* No known domain master browser as yet. */ 112 *work->dmb_name.name = '\0'; 113 zero_ip_v4(&work->dmb_addr); 114 115 /* WfWg uses 01040b01 */ 116 /* Win95 uses 01041501 */ 117 /* NTAS uses ???????? */ 118 work->ElectionCriterion = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8); 119 work->ElectionCriterion |= (lp_os_level() << 24); 120 if (lp_domain_master()) 121 work->ElectionCriterion |= 0x80; 122 123 return work; 124} 125 126/******************************************************************* 127 Remove a workgroup. 128******************************************************************/ 129 130static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec, 131 struct work_record *work) 132{ 133 struct work_record *ret_work = NULL; 134 135 DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group)); 136 137 ret_work = work->next; 138 139 remove_all_servers(work); 140 141 if (!work->serverlist) { 142 if (work->prev) 143 work->prev->next = work->next; 144 if (work->next) 145 work->next->prev = work->prev; 146 147 if (subrec->workgrouplist == work) 148 subrec->workgrouplist = work->next; 149 150 ZERO_STRUCTP(work); 151 SAFE_FREE(work); 152 } 153 154 subrec->work_changed = True; 155 156 return ret_work; 157} 158 159/**************************************************************************** 160 Find a workgroup in the workgroup list of a subnet. 161**************************************************************************/ 162 163struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec, 164 const char *name) 165{ 166 struct work_record *ret; 167 unstring un_name; 168 169 DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ", 170 name, subrec->subnet_name)); 171 172 name_to_unstring(un_name, name); 173 174 for (ret = subrec->workgrouplist; ret; ret = ret->next) { 175 if (strequal(ret->work_group,un_name)) { 176 DEBUGADD(4, ("found.\n")); 177 return(ret); 178 } 179 } 180 DEBUGADD(4, ("not found.\n")); 181 return NULL; 182} 183 184/**************************************************************************** 185 Create a workgroup in the workgroup list of the subnet. 186**************************************************************************/ 187 188struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec, 189 const char *name, int ttl) 190{ 191 struct work_record *work = NULL; 192 193 DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n", 194 name, subrec->subnet_name)); 195 196 if ((work = create_workgroup(name, ttl))) { 197 add_workgroup(subrec, work); 198 subrec->work_changed = True; 199 return(work); 200 } 201 202 return NULL; 203} 204 205/**************************************************************************** 206 Update a workgroup ttl. 207**************************************************************************/ 208 209void update_workgroup_ttl(struct work_record *work, int ttl) 210{ 211 if(work->death_time != PERMANENT_TTL) 212 work->death_time = time(NULL)+(ttl*3); 213 work->subnet->work_changed = True; 214} 215 216/**************************************************************************** 217 Fail function called if we cannot register the WORKGROUP<0> and 218 WORKGROUP<1e> names on the net. 219**************************************************************************/ 220 221static void fail_register(struct subnet_record *subrec, struct response_record *rrec, 222 struct nmb_name *nmbname) 223{ 224 DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n", 225 nmb_namestr(nmbname), subrec->subnet_name)); 226} 227 228/**************************************************************************** 229 If the workgroup is our primary workgroup, add the required names to it. 230**************************************************************************/ 231 232void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work) 233{ 234 int i; 235 236 if(!strequal(lp_workgroup(), work->work_group)) 237 return; 238 239 /* If this is a broadcast subnet then start elections on it if we are so configured. */ 240 241 if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) && 242 (subrec != wins_server_subnet) && lp_preferred_master() && lp_local_master()) { 243 DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \ 244workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name)); 245 work->needelection = True; 246 work->ElectionCriterion |= (1<<3); 247 } 248 249 /* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */ 250 251 register_name(subrec,lp_workgroup(),0x0,samba_nb_type|NB_GROUP, NULL, fail_register,NULL); 252 register_name(subrec,lp_workgroup(),0x1e,samba_nb_type|NB_GROUP, NULL, fail_register,NULL); 253 254 for( i = 0; my_netbios_names(i); i++) { 255 const char *name = my_netbios_names(i); 256 int stype = lp_default_server_announce() | (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0 ); 257 258 if(!strequal(global_myname(), name)) 259 stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER); 260 261 create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY, PERMANENT_TTL, 262 string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH)); 263 DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \ 264on subnet %s\n", name, subrec->subnet_name)); 265 } 266} 267 268/**************************************************************************** 269 Dump a copy of the workgroup database into the log file. 270 **************************************************************************/ 271 272void dump_workgroups(bool force_write) 273{ 274 struct subnet_record *subrec; 275 int debuglevel = force_write ? 0 : 4; 276 277 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) { 278 if (subrec->workgrouplist) { 279 struct work_record *work; 280 281 if( DEBUGLVL( debuglevel ) ) { 282 dbgtext( "dump_workgroups()\n " ); 283 dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name ); 284 dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) ); 285 } 286 287 for (work = subrec->workgrouplist; work; work = work->next) { 288 DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n", work->work_group, 289 work->token, *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ) ); 290 if (work->serverlist) { 291 struct server_record *servrec; 292 for (servrec = work->serverlist; servrec; servrec = servrec->next) { 293 DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n", 294 servrec->serv.name, 295 servrec->serv.type, 296 servrec->serv.comment ) ); 297 } 298 } 299 } 300 } 301 } 302} 303 304/**************************************************************************** 305 Expire any dead servers on all workgroups. If the workgroup has expired 306 remove it. 307 **************************************************************************/ 308 309void expire_workgroups_and_servers(time_t t) 310{ 311 struct subnet_record *subrec; 312 313 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) { 314 struct work_record *work; 315 struct work_record *nextwork; 316 317 for (work = subrec->workgrouplist; work; work = nextwork) { 318 nextwork = work->next; 319 expire_servers(work, t); 320 321 if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) && 322 ((t == (time_t)-1) || (work->death_time < t))) { 323 DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n", 324 work->work_group)); 325 remove_workgroup_from_subnet(subrec, work); 326 } 327 } 328 } 329} 330