Make smbd/posix_acls.c use abstract interface.
[Samba.git] / source / nmbd / nmbd_become_dmb.c
blob76d92c2f3ed9b3a378020b950792351cafeb4857
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
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.
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.
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.
25 #include "includes.h"
27 extern int DEBUGLEVEL;
29 extern pstring global_myname;
30 extern fstring global_myworkgroup;
31 extern char **my_netbios_names;
32 extern struct in_addr ipzero;
33 extern struct in_addr allones_ip;
35 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
37 static void become_domain_master_browser_bcast(char *);
39 /****************************************************************************
40 Fail to become a Domain Master Browser on a subnet.
41 ****************************************************************************/
43 static void become_domain_master_fail(struct subnet_record *subrec,
44 struct response_record *rrec,
45 struct nmb_name *fail_name)
47 struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
48 struct server_record *servrec;
50 if(!work)
52 DEBUG(0,("become_domain_master_fail: Error - cannot find \
53 workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
54 return;
57 /* Set the state back to DOMAIN_NONE. */
58 work->dom_state = DOMAIN_NONE;
60 if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
62 DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
63 in workgroup %s on subnet %s\n",
64 global_myname, work->work_group, subrec->subnet_name));
65 return;
68 /* Update our server status. */
69 servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
71 /* Tell the namelist writer to write out a change. */
72 subrec->work_changed = True;
74 DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
75 workgroup %s on subnet %s. Couldn't register name %s.\n",
76 work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
79 /****************************************************************************
80 Become a Domain Master Browser on a subnet.
81 ****************************************************************************/
83 static void become_domain_master_stage2(struct subnet_record *subrec,
84 struct userdata_struct *userdata,
85 struct nmb_name *registered_name,
86 uint16 nb_flags,
87 int ttl, struct in_addr registered_ip)
89 struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
90 struct server_record *servrec;
92 if(!work)
94 DEBUG(0,("become_domain_master_stage2: Error - cannot find \
95 workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
96 return;
99 if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
101 DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
102 in workgroup %s on subnet %s\n",
103 global_myname, registered_name->name, subrec->subnet_name));
104 work->dom_state = DOMAIN_NONE;
105 return;
108 /* Set the state in the workgroup structure. */
109 work->dom_state = DOMAIN_MST; /* Become domain master. */
111 /* Update our server status. */
112 servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
114 /* Tell the namelist writer to write out a change. */
115 subrec->work_changed = True;
117 if( DEBUGLVL( 0 ) )
119 dbgtext( "*****\n\nSamba server %s ", global_myname );
120 dbgtext( "is now a domain master browser for " );
121 dbgtext( "workgroup %s ", work->work_group );
122 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
125 if( subrec == unicast_subnet )
127 struct nmb_name nmbname;
128 struct in_addr my_first_ip;
130 /* Put our name and first IP address into the
131 workgroup struct as domain master browser. This
132 will stop us syncing with ourself if we are also
133 a local master browser. */
135 make_nmb_name(&nmbname, global_myname, 0x20);
137 work->dmb_name = nmbname;
138 /* Pick the first interface ip address as the domain master browser ip. */
139 my_first_ip = *iface_n_ip(0);
141 putip((char *)&work->dmb_addr, &my_first_ip);
143 /* We successfully registered by unicast with the
144 WINS server. We now expect to become the domain
145 master on the local subnets. If this fails, it's
146 probably a 1.9.16p2 to 1.9.16p11 server's fault.
148 This is a configuration issue that should be addressed
149 by the network administrator - you shouldn't have
150 several machines configured as a domain master browser
151 for the same WINS scope (except if they are 1.9.17 or
152 greater, and you know what you're doing.
154 see docs/DOMAIN.txt.
157 become_domain_master_browser_bcast(work->work_group);
159 else
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.
167 insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
171 /****************************************************************************
172 Start the name registration process when becoming a Domain Master Browser
173 on a subnet.
174 ****************************************************************************/
176 static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name)
178 struct work_record *work;
180 DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
181 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
183 /* First, find the workgroup on the subnet. */
184 if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL)
186 DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
187 wg_name, subrec->subnet_name));
188 return;
191 DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
192 work->dom_state = DOMAIN_WAIT;
194 /* WORKGROUP<1b> is the domain master browser name. */
195 register_name(subrec, work->work_group,0x1b,samba_nb_type,
196 become_domain_master_stage2,
197 become_domain_master_fail, NULL);
200 /****************************************************************************
201 Function called when a query for a WORKGROUP<1b> name succeeds.
202 This is normally a fail condition as it means there is already
203 a domain master browser for a workgroup and we were trying to
204 become one.
205 ****************************************************************************/
207 static void become_domain_master_query_success(struct subnet_record *subrec,
208 struct userdata_struct *userdata,
209 struct nmb_name *nmbname, struct in_addr ip,
210 struct res_rec *rrec)
212 /* If the given ip is not ours, then we can't become a domain
213 controler as the name is already registered.
216 /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
217 address or zero ip for this query. Pretend this is ok. */
219 if(ismyip(ip) || ip_equal(allones_ip, ip) || ip_equal(ipzero, ip))
221 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" );
231 become_domain_master_stage1(subrec, nmbname->name);
233 else
235 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), nmbname->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 /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
256 then this is a failure. Otherwise, not finding the name is what we want. */
257 if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
259 DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
260 querying WINS server for name %s.\n",
261 fail_code, nmb_namestr(question_name)));
262 return;
265 /* Otherwise - not having the name allows us to register it. */
266 become_domain_master_stage1(subrec, question_name->name);
269 /****************************************************************************
270 Attempt to become a domain master browser on all broadcast subnets.
271 ****************************************************************************/
273 static void become_domain_master_browser_bcast(char *workgroup_name)
275 struct subnet_record *subrec;
277 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
279 struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
281 if (work && (work->dom_state == DOMAIN_NONE))
283 struct nmb_name nmbname;
284 make_nmb_name(&nmbname,workgroup_name,0x1b);
287 * Check for our name on the given broadcast subnet first, only initiate
288 * further processing if we cannot find it.
291 if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
293 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 );
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.
306 DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
307 for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
309 query_name(subrec, nmbname.name, nmbname.name_type,
310 become_domain_master_query_success,
311 become_domain_master_query_fail,
312 NULL);
318 /****************************************************************************
319 Attempt to become a domain master browser by registering with WINS.
320 ****************************************************************************/
322 static void become_domain_master_browser_wins(char *workgroup_name)
324 struct work_record *work;
326 work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
328 if (work && (work->dom_state == DOMAIN_NONE))
330 struct nmb_name nmbname;
332 make_nmb_name(&nmbname,workgroup_name,0x1b);
335 * Check for our name on the unicast subnet first, only initiate
336 * further processing if we cannot find it.
339 if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
341 if( DEBUGLVL( 0 ) )
343 dbgtext( "become_domain_master_browser_wins:\n" );
344 dbgtext( "Attempting to become domain master browser " );
345 dbgtext( "on workgroup %s, subnet %s.\n",
346 workgroup_name, unicast_subnet->subnet_name );
349 /* Send out a query to establish whether there's a
350 domain master broswer registered with WINS. If not,
351 we can become a domain master browser.
354 DEBUG(0,("become_domain_master_browser_wins: querying WINS server at IP %s \
355 for domain master browser name %s on workgroup %s\n",
356 inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
358 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
359 become_domain_master_query_success,
360 become_domain_master_query_fail,
361 NULL);
366 /****************************************************************************
367 Add the domain logon server and domain master browser names
368 if we are set up to do so.
369 **************************************************************************/
371 void add_domain_names(time_t t)
373 static time_t lastrun = 0;
375 if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
376 return;
378 lastrun = t;
380 /* Do the "internet group" - <1c> names. */
381 if (lp_domain_logons())
382 add_logon_names();
384 /* Do the domain master names. */
385 if(lp_domain_master())
387 if(we_are_a_wins_client())
389 /* We register the WORKGROUP<1b> name with the WINS
390 server first, and call add_domain_master_bcast()
391 only if this is successful.
393 This results in domain logon services being gracefully provided,
394 as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
395 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
396 cannot provide domain master / domain logon services.
398 become_domain_master_browser_wins(global_myworkgroup);
400 else
401 become_domain_master_browser_bcast(global_myworkgroup);