source: trunk/server/source3/nmbd/nmbd_become_dmb.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 14.2 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 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#include "../librpc/gen_ndr/svcctl.h"
25#include "nmbd/nmbd.h"
26
27extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
28
29static void become_domain_master_browser_bcast(const char *);
30
31/****************************************************************************
32 Fail to become a Domain Master Browser on a subnet.
33 ****************************************************************************/
34
35static void become_domain_master_fail(struct subnet_record *subrec,
36 struct response_record *rrec,
37 struct nmb_name *fail_name)
38{
39 unstring failname;
40 struct work_record *work;
41 struct server_record *servrec;
42
43 pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
44 work = find_workgroup_on_subnet(subrec, failname);
45 if(!work) {
46 DEBUG(0,("become_domain_master_fail: Error - cannot find \
47workgroup %s on subnet %s\n", failname, subrec->subnet_name));
48 return;
49 }
50
51 /* Set the state back to DOMAIN_NONE. */
52 work->dom_state = DOMAIN_NONE;
53
54 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
55 DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
56in workgroup %s on subnet %s\n",
57 global_myname(), work->work_group, subrec->subnet_name));
58 return;
59 }
60
61 /* Update our server status. */
62 servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
63
64 /* Tell the namelist writer to write out a change. */
65 subrec->work_changed = True;
66
67 DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
68workgroup %s on subnet %s. Couldn't register name %s.\n",
69 work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
70}
71
72/****************************************************************************
73 Become a Domain Master Browser on a subnet.
74 ****************************************************************************/
75
76static void become_domain_master_stage2(struct subnet_record *subrec,
77 struct userdata_struct *userdata,
78 struct nmb_name *registered_name,
79 uint16 nb_flags,
80 int ttl, struct in_addr registered_ip)
81{
82 unstring regname;
83 struct work_record *work;
84 struct server_record *servrec;
85
86 pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
87 work = find_workgroup_on_subnet( subrec, regname);
88
89 if(!work) {
90 DEBUG(0,("become_domain_master_stage2: Error - cannot find \
91workgroup %s on subnet %s\n", regname, subrec->subnet_name));
92 return;
93 }
94
95 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
96 DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
97in workgroup %s on subnet %s\n",
98 global_myname(), regname, subrec->subnet_name));
99 work->dom_state = DOMAIN_NONE;
100 return;
101 }
102
103 /* Set the state in the workgroup structure. */
104 work->dom_state = DOMAIN_MST; /* Become domain master. */
105
106 /* Update our server status. */
107 servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
108
109 /* Tell the namelist writer to write out a change. */
110 subrec->work_changed = True;
111
112 if( DEBUGLVL( 0 ) ) {
113 dbgtext( "*****\n\nSamba server %s ", global_myname() );
114 dbgtext( "is now a domain master browser for " );
115 dbgtext( "workgroup %s ", work->work_group );
116 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
117 }
118
119 if( subrec == unicast_subnet ) {
120 struct nmb_name nmbname;
121 struct in_addr my_first_ip;
122 const struct in_addr *nip;
123
124 /* Put our name and first IP address into the
125 workgroup struct as domain master browser. This
126 will stop us syncing with ourself if we are also
127 a local master browser. */
128
129 make_nmb_name(&nmbname, global_myname(), 0x20);
130
131 work->dmb_name = nmbname;
132
133 /* Pick the first interface IPv4 address as the domain master
134 * browser ip. */
135 nip = first_ipv4_iface();
136 if (!nip) {
137 DEBUG(0,("become_domain_master_stage2: "
138 "Error. get_interface returned NULL\n"));
139 return;
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 struct in_addr allones_ip;
213
214 pull_ascii_nstring(name, sizeof(name), nmbname->name);
215
216 /* If the given ip is not ours, then we can't become a domain
217 controler as the name is already registered.
218 */
219
220 /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
221 address or zero ip for this query. Pretend this is ok. */
222
223 allones_ip.s_addr = htonl(INADDR_BROADCAST);
224
225 if(ismyip_v4(ip) || ip_equal_v4(allones_ip, ip) || is_zero_ip_v4(ip)) {
226 if( DEBUGLVL( 3 ) ) {
227 dbgtext( "become_domain_master_query_success():\n" );
228 dbgtext( "Our address (%s) ", inet_ntoa(ip) );
229 dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
230 dbgtext( "(domain master browser name) " );
231 dbgtext( "on subnet %s.\n", subrec->subnet_name );
232 dbgtext( "Continuing with domain master code.\n" );
233 }
234
235 become_domain_master_stage1(subrec, name);
236 } else {
237 if( DEBUGLVL( 0 ) ) {
238 dbgtext( "become_domain_master_query_success:\n" );
239 dbgtext( "There is already a domain master browser at " );
240 dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), name );
241 dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
242 }
243 }
244}
245
246/****************************************************************************
247 Function called when a query for a WORKGROUP<1b> name fails.
248 This is normally a success condition as it then allows us to register
249 our own Domain Master Browser name.
250 ****************************************************************************/
251
252static void become_domain_master_query_fail(struct subnet_record *subrec,
253 struct response_record *rrec,
254 struct nmb_name *question_name, int fail_code)
255{
256 unstring name;
257
258 /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
259 then this is a failure. Otherwise, not finding the name is what we want. */
260
261 if((subrec == unicast_subnet) && (fail_code != NAM_ERR)) {
262 DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
263querying WINS server for name %s.\n",
264 fail_code, nmb_namestr(question_name)));
265 return;
266 }
267
268 /* Otherwise - not having the name allows us to register it. */
269 pull_ascii_nstring(name, sizeof(name), question_name->name);
270 become_domain_master_stage1(subrec, name);
271}
272
273/****************************************************************************
274 Attempt to become a domain master browser on all broadcast subnets.
275 ****************************************************************************/
276
277static void become_domain_master_browser_bcast(const char *workgroup_name)
278{
279 struct subnet_record *subrec;
280
281 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
282 struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
283
284 if (work && (work->dom_state == DOMAIN_NONE)) {
285 struct nmb_name nmbname;
286 make_nmb_name(&nmbname,workgroup_name,0x1b);
287
288 /*
289 * Check for our name on the given broadcast subnet first, only initiate
290 * further processing if we cannot find it.
291 */
292
293 if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
294 if( DEBUGLVL( 0 ) ) {
295 dbgtext( "become_domain_master_browser_bcast:\n" );
296 dbgtext( "Attempting to become domain master browser on " );
297 dbgtext( "workgroup %s on subnet %s\n",
298 workgroup_name, subrec->subnet_name );
299 }
300
301 /* Send out a query to establish whether there's a
302 domain controller on the local subnet. If not,
303 we can become a domain controller.
304 */
305
306 DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
307for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
308
309 query_name(subrec, workgroup_name, nmbname.name_type,
310 become_domain_master_query_success,
311 become_domain_master_query_fail,
312 NULL);
313 }
314 }
315 }
316}
317
318/****************************************************************************
319 Attempt to become a domain master browser by registering with WINS.
320 ****************************************************************************/
321
322static void become_domain_master_browser_wins(const char *workgroup_name)
323{
324 struct work_record *work;
325
326 work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
327
328 if (work && (work->dom_state == DOMAIN_NONE)) {
329 struct nmb_name nmbname;
330
331 make_nmb_name(&nmbname,workgroup_name,0x1b);
332
333 /*
334 * Check for our name on the unicast subnet first, only initiate
335 * further processing if we cannot find it.
336 */
337
338 if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
339 if( DEBUGLVL( 0 ) ) {
340 dbgtext( "become_domain_master_browser_wins:\n" );
341 dbgtext( "Attempting to become domain master browser " );
342 dbgtext( "on workgroup %s, subnet %s.\n",
343 workgroup_name, unicast_subnet->subnet_name );
344 }
345
346 /* Send out a query to establish whether there's a
347 domain master broswer registered with WINS. If not,
348 we can become a domain master browser.
349 */
350
351 DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
352for domain master browser name %s on workgroup %s\n",
353 inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
354
355 query_name(unicast_subnet, workgroup_name, nmbname.name_type,
356 become_domain_master_query_success,
357 become_domain_master_query_fail,
358 NULL);
359 }
360 }
361}
362
363/****************************************************************************
364 Add the domain logon server and domain master browser names
365 if we are set up to do so.
366 **************************************************************************/
367
368void add_domain_names(time_t t)
369{
370 static time_t lastrun = 0;
371
372 if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
373 return;
374
375 lastrun = t;
376
377 /* Do the "internet group" - <1c> names. */
378 if (lp_domain_logons())
379 add_logon_names();
380
381 /* Do the domain master names. */
382 if(lp_domain_master()) {
383 if(we_are_a_wins_client()) {
384 /* We register the WORKGROUP<1b> name with the WINS
385 server first, and call add_domain_master_bcast()
386 only if this is successful.
387
388 This results in domain logon services being gracefully provided,
389 as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
390 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
391 cannot provide domain master / domain logon services.
392 */
393 become_domain_master_browser_wins(lp_workgroup());
394 } else {
395 become_domain_master_browser_bcast(lp_workgroup());
396 }
397 }
398}
Note: See TracBrowser for help on using the repository browser.