~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/nmbd/nmbd_workgroupdb.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
25
extern uint16 samba_nb_type;
 
26
 
 
27
int workgroup_count = 0; /* unique index key: one for each workgroup */
 
28
 
 
29
/****************************************************************************
 
30
  Add a workgroup into the list.
 
31
**************************************************************************/
 
32
 
 
33
static 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
 
 
44
static 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
 
 
65
static 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
 
 
130
static 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
 
 
163
struct 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
 
 
188
struct 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
 
 
209
void 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
     
 
221
static 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
 
 
232
void 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 \
 
244
workgroup %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 \
 
264
on 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
 
 
272
void 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
 
 
309
void 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
}