s3: Lift the server_messaging_context from notify_job_status
[Samba/gbeck.git] / source3 / nmbd / nmbd_become_dmb.c
blob337eae85f5b74b261be85bf13f6d66e7a2df7cab
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
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.
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.
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/>.
23 #include "includes.h"
24 #include "../librpc/gen_ndr/svcctl.h"
26 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
28 static void become_domain_master_browser_bcast(const char *);
30 /****************************************************************************
31 Fail to become a Domain Master Browser on a subnet.
32 ****************************************************************************/
34 static void become_domain_master_fail(struct subnet_record *subrec,
35 struct response_record *rrec,
36 struct nmb_name *fail_name)
38 unstring failname;
39 struct work_record *work;
40 struct server_record *servrec;
42 pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
43 work = find_workgroup_on_subnet(subrec, failname);
44 if(!work) {
45 DEBUG(0,("become_domain_master_fail: Error - cannot find \
46 workgroup %s on subnet %s\n", failname, subrec->subnet_name));
47 return;
50 /* Set the state back to DOMAIN_NONE. */
51 work->dom_state = DOMAIN_NONE;
53 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
54 DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
55 in workgroup %s on subnet %s\n",
56 global_myname(), work->work_group, subrec->subnet_name));
57 return;
60 /* Update our server status. */
61 servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
63 /* Tell the namelist writer to write out a change. */
64 subrec->work_changed = True;
66 DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
67 workgroup %s on subnet %s. Couldn't register name %s.\n",
68 work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
71 /****************************************************************************
72 Become a Domain Master Browser on a subnet.
73 ****************************************************************************/
75 static void become_domain_master_stage2(struct subnet_record *subrec,
76 struct userdata_struct *userdata,
77 struct nmb_name *registered_name,
78 uint16 nb_flags,
79 int ttl, struct in_addr registered_ip)
81 unstring regname;
82 struct work_record *work;
83 struct server_record *servrec;
85 pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
86 work = find_workgroup_on_subnet( subrec, regname);
88 if(!work) {
89 DEBUG(0,("become_domain_master_stage2: Error - cannot find \
90 workgroup %s on subnet %s\n", regname, subrec->subnet_name));
91 return;
94 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
95 DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
96 in workgroup %s on subnet %s\n",
97 global_myname(), regname, subrec->subnet_name));
98 work->dom_state = DOMAIN_NONE;
99 return;
102 /* Set the state in the workgroup structure. */
103 work->dom_state = DOMAIN_MST; /* Become domain master. */
105 /* Update our server status. */
106 servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
108 /* Tell the namelist writer to write out a change. */
109 subrec->work_changed = True;
111 if( DEBUGLVL( 0 ) ) {
112 dbgtext( "*****\n\nSamba server %s ", global_myname() );
113 dbgtext( "is now a domain master browser for " );
114 dbgtext( "workgroup %s ", work->work_group );
115 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
118 if( subrec == unicast_subnet ) {
119 struct nmb_name nmbname;
120 struct in_addr my_first_ip;
121 const struct in_addr *nip;
123 /* Put our name and first IP address into the
124 workgroup struct as domain master browser. This
125 will stop us syncing with ourself if we are also
126 a local master browser. */
128 make_nmb_name(&nmbname, global_myname(), 0x20);
130 work->dmb_name = nmbname;
132 /* Pick the first interface IPv4 address as the domain master
133 * browser ip. */
134 nip = first_ipv4_iface();
135 if (!nip) {
136 DEBUG(0,("become_domain_master_stage2: "
137 "Error. get_interface returned NULL\n"));
138 return;
140 my_first_ip = *nip;
142 putip((char *)&work->dmb_addr, &my_first_ip);
144 /* We successfully registered by unicast with the
145 WINS server. We now expect to become the domain
146 master on the local subnets. If this fails, it's
147 probably a 1.9.16p2 to 1.9.16p11 server's fault.
149 This is a configuration issue that should be addressed
150 by the network administrator - you shouldn't have
151 several machines configured as a domain master browser
152 for the same WINS scope (except if they are 1.9.17 or
153 greater, and you know what you're doing.
155 see docs/DOMAIN.txt.
158 become_domain_master_browser_bcast(work->work_group);
159 } else {
161 * Now we are a domain master on a broadcast subnet, we need to add
162 * the WORKGROUP<1b> name to the unicast subnet so that we can answer
163 * unicast requests sent to this name. This bug wasn't found for a while
164 * as it is strange to have a DMB without using WINS. JRA.
166 insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
170 /****************************************************************************
171 Start the name registration process when becoming a Domain Master Browser
172 on a subnet.
173 ****************************************************************************/
175 static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
177 struct work_record *work;
179 DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
180 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
182 /* First, find the workgroup on the subnet. */
183 if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL) {
184 DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
185 wg_name, subrec->subnet_name));
186 return;
189 DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
190 work->dom_state = DOMAIN_WAIT;
192 /* WORKGROUP<1b> is the domain master browser name. */
193 register_name(subrec, work->work_group,0x1b,samba_nb_type,
194 become_domain_master_stage2,
195 become_domain_master_fail, NULL);
198 /****************************************************************************
199 Function called when a query for a WORKGROUP<1b> name succeeds.
200 This is normally a fail condition as it means there is already
201 a domain master browser for a workgroup and we were trying to
202 become one.
203 ****************************************************************************/
205 static void become_domain_master_query_success(struct subnet_record *subrec,
206 struct userdata_struct *userdata,
207 struct nmb_name *nmbname, struct in_addr ip,
208 struct res_rec *rrec)
210 unstring name;
211 struct in_addr allones_ip;
213 pull_ascii_nstring(name, sizeof(name), nmbname->name);
215 /* If the given ip is not ours, then we can't become a domain
216 controler as the name is already registered.
219 /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
220 address or zero ip for this query. Pretend this is ok. */
222 allones_ip.s_addr = htonl(INADDR_BROADCAST);
224 if(ismyip_v4(ip) || ip_equal_v4(allones_ip, ip) || is_zero_ip_v4(ip)) {
225 if( DEBUGLVL( 3 ) ) {
226 dbgtext( "become_domain_master_query_success():\n" );
227 dbgtext( "Our address (%s) ", inet_ntoa(ip) );
228 dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
229 dbgtext( "(domain master browser name) " );
230 dbgtext( "on subnet %s.\n", subrec->subnet_name );
231 dbgtext( "Continuing with domain master code.\n" );
234 become_domain_master_stage1(subrec, name);
235 } else {
236 if( DEBUGLVL( 0 ) ) {
237 dbgtext( "become_domain_master_query_success:\n" );
238 dbgtext( "There is already a domain master browser at " );
239 dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), name );
240 dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
245 /****************************************************************************
246 Function called when a query for a WORKGROUP<1b> name fails.
247 This is normally a success condition as it then allows us to register
248 our own Domain Master Browser name.
249 ****************************************************************************/
251 static void become_domain_master_query_fail(struct subnet_record *subrec,
252 struct response_record *rrec,
253 struct nmb_name *question_name, int fail_code)
255 unstring name;
257 /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
258 then this is a failure. Otherwise, not finding the name is what we want. */
260 if((subrec == unicast_subnet) && (fail_code != NAM_ERR)) {
261 DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
262 querying WINS server for name %s.\n",
263 fail_code, nmb_namestr(question_name)));
264 return;
267 /* Otherwise - not having the name allows us to register it. */
268 pull_ascii_nstring(name, sizeof(name), question_name->name);
269 become_domain_master_stage1(subrec, name);
272 /****************************************************************************
273 Attempt to become a domain master browser on all broadcast subnets.
274 ****************************************************************************/
276 static void become_domain_master_browser_bcast(const char *workgroup_name)
278 struct subnet_record *subrec;
280 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
281 struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
283 if (work && (work->dom_state == DOMAIN_NONE)) {
284 struct nmb_name nmbname;
285 make_nmb_name(&nmbname,workgroup_name,0x1b);
288 * Check for our name on the given broadcast subnet first, only initiate
289 * further processing if we cannot find it.
292 if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
293 if( DEBUGLVL( 0 ) ) {
294 dbgtext( "become_domain_master_browser_bcast:\n" );
295 dbgtext( "Attempting to become domain master browser on " );
296 dbgtext( "workgroup %s on subnet %s\n",
297 workgroup_name, subrec->subnet_name );
300 /* Send out a query to establish whether there's a
301 domain controller on the local subnet. If not,
302 we can become a domain controller.
305 DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
306 for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
308 query_name(subrec, workgroup_name, nmbname.name_type,
309 become_domain_master_query_success,
310 become_domain_master_query_fail,
311 NULL);
317 /****************************************************************************
318 Attempt to become a domain master browser by registering with WINS.
319 ****************************************************************************/
321 static void become_domain_master_browser_wins(const char *workgroup_name)
323 struct work_record *work;
325 work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
327 if (work && (work->dom_state == DOMAIN_NONE)) {
328 struct nmb_name nmbname;
330 make_nmb_name(&nmbname,workgroup_name,0x1b);
333 * Check for our name on the unicast subnet first, only initiate
334 * further processing if we cannot find it.
337 if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
338 if( DEBUGLVL( 0 ) ) {
339 dbgtext( "become_domain_master_browser_wins:\n" );
340 dbgtext( "Attempting to become domain master browser " );
341 dbgtext( "on workgroup %s, subnet %s.\n",
342 workgroup_name, unicast_subnet->subnet_name );
345 /* Send out a query to establish whether there's a
346 domain master broswer registered with WINS. If not,
347 we can become a domain master browser.
350 DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
351 for domain master browser name %s on workgroup %s\n",
352 inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
354 query_name(unicast_subnet, workgroup_name, nmbname.name_type,
355 become_domain_master_query_success,
356 become_domain_master_query_fail,
357 NULL);
362 /****************************************************************************
363 Add the domain logon server and domain master browser names
364 if we are set up to do so.
365 **************************************************************************/
367 void add_domain_names(time_t t)
369 static time_t lastrun = 0;
371 if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
372 return;
374 lastrun = t;
376 /* Do the "internet group" - <1c> names. */
377 if (lp_domain_logons())
378 add_logon_names();
380 /* Do the domain master names. */
381 if(lp_domain_master()) {
382 if(we_are_a_wins_client()) {
383 /* We register the WORKGROUP<1b> name with the WINS
384 server first, and call add_domain_master_bcast()
385 only if this is successful.
387 This results in domain logon services being gracefully provided,
388 as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
389 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
390 cannot provide domain master / domain logon services.
392 become_domain_master_browser_wins(lp_workgroup());
393 } else {
394 become_domain_master_browser_bcast(lp_workgroup());