337eae85f5b74b261be85bf13f6d66e7a2df7cab
[metze/samba/wip.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 #include "../librpc/gen_ndr/svcctl.h"
25
26 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
27
28 static void become_domain_master_browser_bcast(const char *);
29
30 /****************************************************************************
31   Fail to become a Domain Master Browser on a subnet.
32   ****************************************************************************/
33
34 static void become_domain_master_fail(struct subnet_record *subrec,
35                                       struct response_record *rrec,
36                                       struct nmb_name *fail_name)
37 {
38         unstring failname;
39         struct work_record *work;
40         struct server_record *servrec;
41
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;
48         }
49
50         /* Set the state back to DOMAIN_NONE. */
51         work->dom_state = DOMAIN_NONE;
52
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;
58         }
59
60         /* Update our server status. */
61         servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
62
63         /* Tell the namelist writer to write out a change. */
64         subrec->work_changed = True;
65
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)));
69 }
70
71 /****************************************************************************
72   Become a Domain Master Browser on a subnet.
73   ****************************************************************************/
74
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)
80 {
81         unstring regname;
82         struct work_record *work;
83         struct server_record *servrec;
84
85         pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
86         work = find_workgroup_on_subnet( subrec, regname);
87
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;
92         }
93
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;
100         }
101
102         /* Set the state in the workgroup structure. */
103         work->dom_state = DOMAIN_MST; /* Become domain master. */
104
105         /* Update our server status. */
106         servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
107
108         /* Tell the namelist writer to write out a change. */
109         subrec->work_changed = True;
110
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 );
116         }
117
118         if( subrec == unicast_subnet ) {
119                 struct nmb_name nmbname;
120                 struct in_addr my_first_ip;
121                 const struct in_addr *nip;
122
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. */
127
128                 make_nmb_name(&nmbname, global_myname(), 0x20);
129
130                 work->dmb_name = nmbname;
131
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;
139                 }
140                 my_first_ip = *nip;
141
142                 putip((char *)&work->dmb_addr, &my_first_ip);
143
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.
148
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.
154
155                    see docs/DOMAIN.txt.
156
157                 */
158                 become_domain_master_browser_bcast(work->work_group);
159         } else {
160                 /*
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.
165                  */
166                 insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
167         }
168 }
169
170 /****************************************************************************
171   Start the name registration process when becoming a Domain Master Browser
172   on a subnet.
173 ****************************************************************************/
174
175 static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
176
177         struct work_record *work;
178
179         DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
180 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
181
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;
187         }
188
189         DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
190         work->dom_state = DOMAIN_WAIT;
191
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);
196 }
197
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 ****************************************************************************/
204
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)
209 {
210         unstring name;
211         struct in_addr allones_ip;
212
213         pull_ascii_nstring(name, sizeof(name), nmbname->name);
214
215         /* If the given ip is not ours, then we can't become a domain
216                 controler as the name is already registered.
217         */
218
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. */
221
222         allones_ip.s_addr = htonl(INADDR_BROADCAST);
223
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" );
232                 }
233
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 );
241                 }
242         }
243 }
244
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   ****************************************************************************/
250
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)
254 {
255         unstring name;
256
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. */
259
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;
265         }
266
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);
270 }
271
272 /****************************************************************************
273   Attempt to become a domain master browser on all broadcast subnets.
274   ****************************************************************************/
275
276 static void become_domain_master_browser_bcast(const char *workgroup_name)
277 {
278         struct subnet_record *subrec;
279
280         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 
281                 struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
282
283                 if (work && (work->dom_state == DOMAIN_NONE)) {
284                         struct nmb_name nmbname;
285                         make_nmb_name(&nmbname,workgroup_name,0x1b);
286
287                         /*
288                          * Check for our name on the given broadcast subnet first, only initiate
289                          * further processing if we cannot find it.
290                          */
291
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 );
298                                 }
299
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. 
303                                 */
304
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));
307
308                                 query_name(subrec, workgroup_name, nmbname.name_type,
309                                         become_domain_master_query_success, 
310                                         become_domain_master_query_fail,
311                                         NULL);
312                         }
313                 }
314         }
315 }
316
317 /****************************************************************************
318   Attempt to become a domain master browser by registering with WINS.
319   ****************************************************************************/
320
321 static void become_domain_master_browser_wins(const char *workgroup_name)
322 {
323         struct work_record *work;
324
325         work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
326
327         if (work && (work->dom_state == DOMAIN_NONE)) {
328                 struct nmb_name nmbname;
329
330                 make_nmb_name(&nmbname,workgroup_name,0x1b);
331
332                 /*
333                  * Check for our name on the unicast subnet first, only initiate
334                  * further processing if we cannot find it.
335                  */
336
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 );
343                         }
344
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. 
348                         */
349
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));
353
354                         query_name(unicast_subnet, workgroup_name, nmbname.name_type,
355                                 become_domain_master_query_success,
356                                 become_domain_master_query_fail,
357                                 NULL);
358                 }
359         }
360 }
361
362 /****************************************************************************
363   Add the domain logon server and domain master browser names
364   if we are set up to do so.
365   **************************************************************************/
366
367 void add_domain_names(time_t t)
368 {
369         static time_t lastrun = 0;
370
371         if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
372                 return;
373
374         lastrun = t;
375
376         /* Do the "internet group" - <1c> names. */
377         if (lp_domain_logons())
378                 add_logon_names();
379
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.
386
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.
391                         */
392                         become_domain_master_browser_wins(lp_workgroup());
393                 } else {
394                         become_domain_master_browser_bcast(lp_workgroup());
395                 }
396         }
397 }