source: branches/samba-3.0/source/nmbd/nmbd_become_dmb.c@ 612

Last change on this file since 612 was 1, checked in by Paul Smedley, 19 years ago

Initial code import

File size: 13.7 KB
Line 
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-2003
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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23
24#include "includes.h"
25
26extern struct in_addr allones_ip;
27
28extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
29
30static void become_domain_master_browser_bcast(const char *);
31
32/****************************************************************************
33 Fail to become a Domain Master Browser on a subnet.
34 ****************************************************************************/
35
36static void become_domain_master_fail(struct subnet_record *subrec,
37 struct response_record *rrec,
38 struct nmb_name *fail_name)
39{
40 unstring failname;
41 struct work_record *work;
42 struct server_record *servrec;
43
44 pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
45 work = find_workgroup_on_subnet(subrec, failname);
46 if(!work) {
47 DEBUG(0,("become_domain_master_fail: Error - cannot find \
48workgroup %s on subnet %s\n", failname, subrec->subnet_name));
49 return;
50 }
51
52 /* Set the state back to DOMAIN_NONE. */
53 work->dom_state = DOMAIN_NONE;
54
55 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
56 DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
57in workgroup %s on subnet %s\n",
58 global_myname(), work->work_group, subrec->subnet_name));
59 return;
60 }
61
62 /* Update our server status. */
63 servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
64
65 /* Tell the namelist writer to write out a change. */
66 subrec->work_changed = True;
67
68 DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
69workgroup %s on subnet %s. Couldn't register name %s.\n",
70 work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
71}
72
73/****************************************************************************
74 Become a Domain Master Browser on a subnet.
75 ****************************************************************************/
76
77static void become_domain_master_stage2(struct subnet_record *subrec,
78 struct userdata_struct *userdata,
79 struct nmb_name *registered_name,
80 uint16 nb_flags,
81 int ttl, struct in_addr registered_ip)
82{
83 unstring regname;
84 struct work_record *work;
85 struct server_record *servrec;
86
87 pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
88 work = find_workgroup_on_subnet( subrec, regname);
89
90 if(!work) {
91 DEBUG(0,("become_domain_master_stage2: Error - cannot find \
92workgroup %s on subnet %s\n", regname, subrec->subnet_name));
93 return;
94 }
95
96 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
97 DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
98in workgroup %s on subnet %s\n",
99 global_myname(), regname, subrec->subnet_name));
100 work->dom_state = DOMAIN_NONE;
101 return;
102 }
103
104 /* Set the state in the workgroup structure. */
105 work->dom_state = DOMAIN_MST; /* Become domain master. */
106
107 /* Update our server status. */
108 servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
109
110 /* Tell the namelist writer to write out a change. */
111 subrec->work_changed = True;
112
113 if( DEBUGLVL( 0 ) ) {
114 dbgtext( "*****\n\nSamba server %s ", global_myname() );
115 dbgtext( "is now a domain master browser for " );
116 dbgtext( "workgroup %s ", work->work_group );
117 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
118 }
119
120 if( subrec == unicast_subnet ) {
121 struct nmb_name nmbname;
122 struct in_addr my_first_ip;
123 struct in_addr *nip;
124
125 /* Put our name and first IP address into the
126 workgroup struct as domain master browser. This
127 will stop us syncing with ourself if we are also
128 a local master browser. */
129
130 make_nmb_name(&nmbname, global_myname(), 0x20);
131
132 work->dmb_name = nmbname;
133 /* Pick the first interface ip address as the domain master browser ip. */
134 nip = iface_n_ip(0);
135
136 if (!nip) {
137 DEBUG(0,("become_domain_master_stage2: Error. iface_n_ip returned NULL\n"));
138 return;
139 }
140
141 my_first_ip = *nip;
142
143 putip((char *)&work->dmb_addr, &my_first_ip);
144
145 /* We successfully registered by unicast with the
146 WINS server. We now expect to become the domain
147 master on the local subnets. If this fails, it's
148 probably a 1.9.16p2 to 1.9.16p11 server's fault.
149
150 This is a configuration issue that should be addressed
151 by the network administrator - you shouldn't have
152 several machines configured as a domain master browser
153 for the same WINS scope (except if they are 1.9.17 or
154 greater, and you know what you're doing.
155
156 see docs/DOMAIN.txt.
157
158 */
159 become_domain_master_browser_bcast(work->work_group);
160 } else {
161 /*
162 * Now we are a domain master on a broadcast subnet, we need to add
163 * the WORKGROUP<1b> name to the unicast subnet so that we can answer
164 * unicast requests sent to this name. This bug wasn't found for a while
165 * as it is strange to have a DMB without using WINS. JRA.
166 */
167 insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
168 }
169}
170
171/****************************************************************************
172 Start the name registration process when becoming a Domain Master Browser
173 on a subnet.
174****************************************************************************/
175
176static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
177{
178 struct work_record *work;
179
180 DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
181workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
182
183 /* First, find the workgroup on the subnet. */
184 if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL) {
185 DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
186 wg_name, subrec->subnet_name));
187 return;
188 }
189
190 DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
191 work->dom_state = DOMAIN_WAIT;
192
193 /* WORKGROUP<1b> is the domain master browser name. */
194 register_name(subrec, work->work_group,0x1b,samba_nb_type,
195 become_domain_master_stage2,
196 become_domain_master_fail, NULL);
197}
198
199/****************************************************************************
200 Function called when a query for a WORKGROUP<1b> name succeeds.
201 This is normally a fail condition as it means there is already
202 a domain master browser for a workgroup and we were trying to
203 become one.
204****************************************************************************/
205
206static void become_domain_master_query_success(struct subnet_record *subrec,
207 struct userdata_struct *userdata,
208 struct nmb_name *nmbname, struct in_addr ip,
209 struct res_rec *rrec)
210{
211 unstring name;
212 pull_ascii_nstring(name, sizeof(name), nmbname->name);
213
214 /* If the given ip is not ours, then we can't become a domain
215 controler as the name is already registered.
216 */
217
218 /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
219 address or zero ip for this query. Pretend this is ok. */
220
221 if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip)) {
222 if( DEBUGLVL( 3 ) ) {
223 dbgtext( "become_domain_master_query_success():\n" );
224 dbgtext( "Our address (%s) ", inet_ntoa(ip) );
225 dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
226 dbgtext( "(domain master browser name) " );
227 dbgtext( "on subnet %s.\n", subrec->subnet_name );
228 dbgtext( "Continuing with domain master code.\n" );
229 }
230
231 become_domain_master_stage1(subrec, name);
232 } else {
233 if( DEBUGLVL( 0 ) ) {
234 dbgtext( "become_domain_master_query_success:\n" );
235 dbgtext( "There is already a domain master browser at " );
236 dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), name );
237 dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
238 }
239 }
240}
241
242/****************************************************************************
243 Function called when a query for a WORKGROUP<1b> name fails.
244 This is normally a success condition as it then allows us to register
245 our own Domain Master Browser name.
246 ****************************************************************************/
247
248static void become_domain_master_query_fail(struct subnet_record *subrec,
249 struct response_record *rrec,
250 struct nmb_name *question_name, int fail_code)
251{
252 unstring name;
253
254 /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
255 then this is a failure. Otherwise, not finding the name is what we want. */
256
257 if((subrec == unicast_subnet) && (fail_code != NAM_ERR)) {
258 DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
259querying WINS server for name %s.\n",
260 fail_code, nmb_namestr(question_name)));
261 return;
262 }
263
264 /* Otherwise - not having the name allows us to register it. */
265 pull_ascii_nstring(name, sizeof(name), question_name->name);
266 become_domain_master_stage1(subrec, name);
267}
268
269/****************************************************************************
270 Attempt to become a domain master browser on all broadcast subnets.
271 ****************************************************************************/
272
273static void become_domain_master_browser_bcast(const char *workgroup_name)
274{
275 struct subnet_record *subrec;
276
277 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
278 struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
279
280 if (work && (work->dom_state == DOMAIN_NONE)) {
281 struct nmb_name nmbname;
282 make_nmb_name(&nmbname,workgroup_name,0x1b);
283
284 /*
285 * Check for our name on the given broadcast subnet first, only initiate
286 * further processing if we cannot find it.
287 */
288
289 if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
290 if( DEBUGLVL( 0 ) ) {
291 dbgtext( "become_domain_master_browser_bcast:\n" );
292 dbgtext( "Attempting to become domain master browser on " );
293 dbgtext( "workgroup %s on subnet %s\n",
294 workgroup_name, subrec->subnet_name );
295 }
296
297 /* Send out a query to establish whether there's a
298 domain controller on the local subnet. If not,
299 we can become a domain controller.
300 */
301
302 DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
303for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
304
305 query_name(subrec, workgroup_name, nmbname.name_type,
306 become_domain_master_query_success,
307 become_domain_master_query_fail,
308 NULL);
309 }
310 }
311 }
312}
313
314/****************************************************************************
315 Attempt to become a domain master browser by registering with WINS.
316 ****************************************************************************/
317
318static void become_domain_master_browser_wins(const char *workgroup_name)
319{
320 struct work_record *work;
321
322 work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
323
324 if (work && (work->dom_state == DOMAIN_NONE)) {
325 struct nmb_name nmbname;
326
327 make_nmb_name(&nmbname,workgroup_name,0x1b);
328
329 /*
330 * Check for our name on the unicast subnet first, only initiate
331 * further processing if we cannot find it.
332 */
333
334 if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
335 if( DEBUGLVL( 0 ) ) {
336 dbgtext( "become_domain_master_browser_wins:\n" );
337 dbgtext( "Attempting to become domain master browser " );
338 dbgtext( "on workgroup %s, subnet %s.\n",
339 workgroup_name, unicast_subnet->subnet_name );
340 }
341
342 /* Send out a query to establish whether there's a
343 domain master broswer registered with WINS. If not,
344 we can become a domain master browser.
345 */
346
347 DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
348for domain master browser name %s on workgroup %s\n",
349 inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
350
351 query_name(unicast_subnet, workgroup_name, nmbname.name_type,
352 become_domain_master_query_success,
353 become_domain_master_query_fail,
354 NULL);
355 }
356 }
357}
358
359/****************************************************************************
360 Add the domain logon server and domain master browser names
361 if we are set up to do so.
362 **************************************************************************/
363
364void add_domain_names(time_t t)
365{
366 static time_t lastrun = 0;
367
368 if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
369 return;
370
371 lastrun = t;
372
373 /* Do the "internet group" - <1c> names. */
374 if (lp_domain_logons())
375 add_logon_names();
376
377 /* Do the domain master names. */
378 if(lp_domain_master()) {
379 if(we_are_a_wins_client()) {
380 /* We register the WORKGROUP<1b> name with the WINS
381 server first, and call add_domain_master_bcast()
382 only if this is successful.
383
384 This results in domain logon services being gracefully provided,
385 as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
386 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
387 cannot provide domain master / domain logon services.
388 */
389 become_domain_master_browser_wins(lp_workgroup());
390 } else {
391 become_domain_master_browser_bcast(lp_workgroup());
392 }
393 }
394}
Note: See TracBrowser for help on using the repository browser.