Replace cli_rpc_pipe_close by a talloc destructor on rpc_pipe_struct
[Samba.git] / source / nmbd / nmbd_become_dmb.c
bloba0b2ef15f8b804c6e2a2be874d3304969c6df84f
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"
25 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
27 static void become_domain_master_browser_bcast(const char *);
29 /****************************************************************************
30 Fail to become a Domain Master Browser on a subnet.
31 ****************************************************************************/
33 static void become_domain_master_fail(struct subnet_record *subrec,
34 struct response_record *rrec,
35 struct nmb_name *fail_name)
37 unstring failname;
38 struct work_record *work;
39 struct server_record *servrec;
41 pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
42 work = find_workgroup_on_subnet(subrec, failname);
43 if(!work) {
44 DEBUG(0,("become_domain_master_fail: Error - cannot find \
45 workgroup %s on subnet %s\n", failname, subrec->subnet_name));
46 return;
49 /* Set the state back to DOMAIN_NONE. */
50 work->dom_state = DOMAIN_NONE;
52 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
53 DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
54 in workgroup %s on subnet %s\n",
55 global_myname(), work->work_group, subrec->subnet_name));
56 return;
59 /* Update our server status. */
60 servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
62 /* Tell the namelist writer to write out a change. */
63 subrec->work_changed = True;
65 DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
66 workgroup %s on subnet %s. Couldn't register name %s.\n",
67 work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
70 /****************************************************************************
71 Become a Domain Master Browser on a subnet.
72 ****************************************************************************/
74 static void become_domain_master_stage2(struct subnet_record *subrec,
75 struct userdata_struct *userdata,
76 struct nmb_name *registered_name,
77 uint16 nb_flags,
78 int ttl, struct in_addr registered_ip)
80 unstring regname;
81 struct work_record *work;
82 struct server_record *servrec;
84 pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
85 work = find_workgroup_on_subnet( subrec, regname);
87 if(!work) {
88 DEBUG(0,("become_domain_master_stage2: Error - cannot find \
89 workgroup %s on subnet %s\n", regname, subrec->subnet_name));
90 return;
93 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
94 DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
95 in workgroup %s on subnet %s\n",
96 global_myname(), regname, subrec->subnet_name));
97 work->dom_state = DOMAIN_NONE;
98 return;
101 /* Set the state in the workgroup structure. */
102 work->dom_state = DOMAIN_MST; /* Become domain master. */
104 /* Update our server status. */
105 servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
107 /* Tell the namelist writer to write out a change. */
108 subrec->work_changed = True;
110 if( DEBUGLVL( 0 ) ) {
111 dbgtext( "*****\n\nSamba server %s ", global_myname() );
112 dbgtext( "is now a domain master browser for " );
113 dbgtext( "workgroup %s ", work->work_group );
114 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
117 if( subrec == unicast_subnet ) {
118 struct nmb_name nmbname;
119 struct in_addr my_first_ip;
120 const struct in_addr *nip;
122 /* Put our name and first IP address into the
123 workgroup struct as domain master browser. This
124 will stop us syncing with ourself if we are also
125 a local master browser. */
127 make_nmb_name(&nmbname, global_myname(), 0x20);
129 work->dmb_name = nmbname;
131 /* Pick the first interface IPv4 address as the domain master browser ip. */
132 nip = first_ipv4_iface();
133 if (!nip) {
134 DEBUG(0,("become_domain_master_stage2: "
135 "Error. get_interface returned NULL\n"));
136 return;
138 my_first_ip = *nip;
140 putip((char *)&work->dmb_addr, &my_first_ip);
142 /* We successfully registered by unicast with the
143 WINS server. We now expect to become the domain
144 master on the local subnets. If this fails, it's
145 probably a 1.9.16p2 to 1.9.16p11 server's fault.
147 This is a configuration issue that should be addressed
148 by the network administrator - you shouldn't have
149 several machines configured as a domain master browser
150 for the same WINS scope (except if they are 1.9.17 or
151 greater, and you know what you're doing.
153 see docs/DOMAIN.txt.
156 become_domain_master_browser_bcast(work->work_group);
157 } else {
159 * Now we are a domain master on a broadcast subnet, we need to add
160 * the WORKGROUP<1b> name to the unicast subnet so that we can answer
161 * unicast requests sent to this name. This bug wasn't found for a while
162 * as it is strange to have a DMB without using WINS. JRA.
164 insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
168 /****************************************************************************
169 Start the name registration process when becoming a Domain Master Browser
170 on a subnet.
171 ****************************************************************************/
173 static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
175 struct work_record *work;
177 DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
178 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
180 /* First, find the workgroup on the subnet. */
181 if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL) {
182 DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
183 wg_name, subrec->subnet_name));
184 return;
187 DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
188 work->dom_state = DOMAIN_WAIT;
190 /* WORKGROUP<1b> is the domain master browser name. */
191 register_name(subrec, work->work_group,0x1b,samba_nb_type,
192 become_domain_master_stage2,
193 become_domain_master_fail, NULL);
196 /****************************************************************************
197 Function called when a query for a WORKGROUP<1b> name succeeds.
198 This is normally a fail condition as it means there is already
199 a domain master browser for a workgroup and we were trying to
200 become one.
201 ****************************************************************************/
203 static void become_domain_master_query_success(struct subnet_record *subrec,
204 struct userdata_struct *userdata,
205 struct nmb_name *nmbname, struct in_addr ip,
206 struct res_rec *rrec)
208 unstring name;
209 struct in_addr allones_ip;
211 pull_ascii_nstring(name, sizeof(name), nmbname->name);
213 /* If the given ip is not ours, then we can't become a domain
214 controler as the name is already registered.
217 /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
218 address or zero ip for this query. Pretend this is ok. */
220 allones_ip.s_addr = htonl(INADDR_BROADCAST);
222 if(ismyip_v4(ip) || ip_equal_v4(allones_ip, ip) || is_zero_ip_v4(ip)) {
223 if( DEBUGLVL( 3 ) ) {
224 dbgtext( "become_domain_master_query_success():\n" );
225 dbgtext( "Our address (%s) ", inet_ntoa(ip) );
226 dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
227 dbgtext( "(domain master browser name) " );
228 dbgtext( "on subnet %s.\n", subrec->subnet_name );
229 dbgtext( "Continuing with domain master code.\n" );
232 become_domain_master_stage1(subrec, name);
233 } else {
234 if( DEBUGLVL( 0 ) ) {
235 dbgtext( "become_domain_master_query_success:\n" );
236 dbgtext( "There is already a domain master browser at " );
237 dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), name );
238 dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
243 /****************************************************************************
244 Function called when a query for a WORKGROUP<1b> name fails.
245 This is normally a success condition as it then allows us to register
246 our own Domain Master Browser name.
247 ****************************************************************************/
249 static void become_domain_master_query_fail(struct subnet_record *subrec,
250 struct response_record *rrec,
251 struct nmb_name *question_name, int fail_code)
253 unstring name;
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. */
258 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 pull_ascii_nstring(name, sizeof(name), question_name->name);
267 become_domain_master_stage1(subrec, name);
270 /****************************************************************************
271 Attempt to become a domain master browser on all broadcast subnets.
272 ****************************************************************************/
274 static void become_domain_master_browser_bcast(const char *workgroup_name)
276 struct subnet_record *subrec;
278 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)) {
282 struct nmb_name nmbname;
283 make_nmb_name(&nmbname,workgroup_name,0x1b);
286 * Check for our name on the given broadcast subnet first, only initiate
287 * further processing if we cannot find it.
290 if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
291 if( DEBUGLVL( 0 ) ) {
292 dbgtext( "become_domain_master_browser_bcast:\n" );
293 dbgtext( "Attempting to become domain master browser on " );
294 dbgtext( "workgroup %s on subnet %s\n",
295 workgroup_name, subrec->subnet_name );
298 /* Send out a query to establish whether there's a
299 domain controller on the local subnet. If not,
300 we can become a domain controller.
303 DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
304 for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
306 query_name(subrec, workgroup_name, nmbname.name_type,
307 become_domain_master_query_success,
308 become_domain_master_query_fail,
309 NULL);
315 /****************************************************************************
316 Attempt to become a domain master browser by registering with WINS.
317 ****************************************************************************/
319 static void become_domain_master_browser_wins(const char *workgroup_name)
321 struct work_record *work;
323 work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
325 if (work && (work->dom_state == DOMAIN_NONE)) {
326 struct nmb_name nmbname;
328 make_nmb_name(&nmbname,workgroup_name,0x1b);
331 * Check for our name on the unicast subnet first, only initiate
332 * further processing if we cannot find it.
335 if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
336 if( DEBUGLVL( 0 ) ) {
337 dbgtext( "become_domain_master_browser_wins:\n" );
338 dbgtext( "Attempting to become domain master browser " );
339 dbgtext( "on workgroup %s, subnet %s.\n",
340 workgroup_name, unicast_subnet->subnet_name );
343 /* Send out a query to establish whether there's a
344 domain master broswer registered with WINS. If not,
345 we can become a domain master browser.
348 DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
349 for domain master browser name %s on workgroup %s\n",
350 inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
352 query_name(unicast_subnet, workgroup_name, nmbname.name_type,
353 become_domain_master_query_success,
354 become_domain_master_query_fail,
355 NULL);
360 /****************************************************************************
361 Add the domain logon server and domain master browser names
362 if we are set up to do so.
363 **************************************************************************/
365 void add_domain_names(time_t t)
367 static time_t lastrun = 0;
369 if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
370 return;
372 lastrun = t;
374 /* Do the "internet group" - <1c> names. */
375 if (lp_domain_logons())
376 add_logon_names();
378 /* Do the domain master names. */
379 if(lp_domain_master()) {
380 if(we_are_a_wins_client()) {
381 /* We register the WORKGROUP<1b> name with the WINS
382 server first, and call add_domain_master_bcast()
383 only if this is successful.
385 This results in domain logon services being gracefully provided,
386 as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
387 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
388 cannot provide domain master / domain logon services.
390 become_domain_master_browser_wins(lp_workgroup());
391 } else {
392 become_domain_master_browser_bcast(lp_workgroup());