Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
[samba.git] / source3 / nmbd / nmbd_become_dmb.c
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
25 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
26
27 static void become_domain_master_browser_bcast(const char *);
28
29 /****************************************************************************
30   Fail to become a Domain Master Browser on a subnet.
31   ****************************************************************************/
32
33 static void become_domain_master_fail(struct subnet_record *subrec,
34                                       struct response_record *rrec,
35                                       struct nmb_name *fail_name)
36 {
37         unstring failname;
38         struct work_record *work;
39         struct server_record *servrec;
40
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;
47         }
48
49         /* Set the state back to DOMAIN_NONE. */
50         work->dom_state = DOMAIN_NONE;
51
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;
57         }
58
59         /* Update our server status. */
60         servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
61
62         /* Tell the namelist writer to write out a change. */
63         subrec->work_changed = True;
64
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)));
68 }
69
70 /****************************************************************************
71   Become a Domain Master Browser on a subnet.
72   ****************************************************************************/
73
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)
79 {
80         unstring regname;
81         struct work_record *work;
82         struct server_record *servrec;
83
84         pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
85         work = find_workgroup_on_subnet( subrec, regname);
86
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;
91         }
92
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;
99         }
100
101         /* Set the state in the workgroup structure. */
102         work->dom_state = DOMAIN_MST; /* Become domain master. */
103
104         /* Update our server status. */
105         servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
106
107         /* Tell the namelist writer to write out a change. */
108         subrec->work_changed = True;
109
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 );
115         }
116
117         if( subrec == unicast_subnet ) {
118                 struct nmb_name nmbname;
119                 struct in_addr my_first_ip;
120                 const struct in_addr *nip;
121
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. */
126
127                 make_nmb_name(&nmbname, global_myname(), 0x20);
128
129                 work->dmb_name = nmbname;
130
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;
137                 }
138                 my_first_ip = *nip;
139
140                 putip((char *)&work->dmb_addr, &my_first_ip);
141
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.
146
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.
152
153                    see docs/DOMAIN.txt.
154
155                 */
156                 become_domain_master_browser_bcast(work->work_group);
157         } else {
158                 /*
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.
163                  */
164                 insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
165         }
166 }
167
168 /****************************************************************************
169   Start the name registration process when becoming a Domain Master Browser
170   on a subnet.
171 ****************************************************************************/
172
173 static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
174
175         struct work_record *work;
176
177         DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
178 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
179
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;
185         }
186
187         DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
188         work->dom_state = DOMAIN_WAIT;
189
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);
194 }
195
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 ****************************************************************************/
202
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)
207 {
208         unstring name;
209         struct in_addr allones_ip;
210
211         pull_ascii_nstring(name, sizeof(name), nmbname->name);
212
213         /* If the given ip is not ours, then we can't become a domain
214                 controler as the name is already registered.
215         */
216
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. */
219
220         allones_ip.s_addr = htonl(INADDR_BROADCAST);
221
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" );
230                 }
231
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 );
239                 }
240         }
241 }
242
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   ****************************************************************************/
248
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)
252 {
253         unstring name;
254
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
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;
263         }
264
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);
268 }
269
270 /****************************************************************************
271   Attempt to become a domain master browser on all broadcast subnets.
272   ****************************************************************************/
273
274 static void become_domain_master_browser_bcast(const char *workgroup_name)
275 {
276         struct subnet_record *subrec;
277
278         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 
279                 struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
280
281                 if (work && (work->dom_state == DOMAIN_NONE)) {
282                         struct nmb_name nmbname;
283                         make_nmb_name(&nmbname,workgroup_name,0x1b);
284
285                         /*
286                          * Check for our name on the given broadcast subnet first, only initiate
287                          * further processing if we cannot find it.
288                          */
289
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 );
296                                 }
297
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. 
301                                 */
302
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));
305
306                                 query_name(subrec, workgroup_name, nmbname.name_type,
307                                         become_domain_master_query_success, 
308                                         become_domain_master_query_fail,
309                                         NULL);
310                         }
311                 }
312         }
313 }
314
315 /****************************************************************************
316   Attempt to become a domain master browser by registering with WINS.
317   ****************************************************************************/
318
319 static void become_domain_master_browser_wins(const char *workgroup_name)
320 {
321         struct work_record *work;
322
323         work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
324
325         if (work && (work->dom_state == DOMAIN_NONE)) {
326                 struct nmb_name nmbname;
327
328                 make_nmb_name(&nmbname,workgroup_name,0x1b);
329
330                 /*
331                  * Check for our name on the unicast subnet first, only initiate
332                  * further processing if we cannot find it.
333                  */
334
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 );
341                         }
342
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. 
346                         */
347
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));
351
352                         query_name(unicast_subnet, workgroup_name, nmbname.name_type,
353                                 become_domain_master_query_success,
354                                 become_domain_master_query_fail,
355                                 NULL);
356                 }
357         }
358 }
359
360 /****************************************************************************
361   Add the domain logon server and domain master browser names
362   if we are set up to do so.
363   **************************************************************************/
364
365 void add_domain_names(time_t t)
366 {
367         static time_t lastrun = 0;
368
369         if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
370                 return;
371
372         lastrun = t;
373
374         /* Do the "internet group" - <1c> names. */
375         if (lp_domain_logons())
376                 add_logon_names();
377
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.
384
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.
389                         */
390                         become_domain_master_browser_wins(lp_workgroup());
391                 } else {
392                         become_domain_master_browser_bcast(lp_workgroup());
393                 }
394         }
395 }