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