first public release of samba4 code
[bbaumbach/samba-autobuild/.git] / source4 / 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-1998
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21    
22 */
23
24 #include "includes.h"
25
26 extern struct in_addr allones_ip;
27
28 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
29
30 static void become_domain_master_browser_bcast(const char *);
31
32 /****************************************************************************
33   Fail to become a Domain Master Browser on a subnet.
34   ****************************************************************************/
35
36 static void become_domain_master_fail(struct subnet_record *subrec,
37                                       struct response_record *rrec,
38                                       struct nmb_name *fail_name)
39 {
40   struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
41   struct server_record *servrec;
42
43   if(!work)
44   {
45     DEBUG(0,("become_domain_master_fail: Error - cannot find \
46 workgroup %s on subnet %s\n", fail_name->name, 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, lp_netbios_name())) == NULL)
54   {
55     DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
56 in workgroup %s on subnet %s\n",
57              lp_netbios_name(), work->work_group, subrec->subnet_name));
58     return;
59   }
60
61   /* Update our server status. */
62   servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
63
64   /* Tell the namelist writer to write out a change. */
65   subrec->work_changed = True;
66
67   DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
68 workgroup %s on subnet %s. Couldn't register name %s.\n",
69        work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
70 }
71
72 /****************************************************************************
73   Become a Domain Master Browser on a subnet.
74   ****************************************************************************/
75
76 static void become_domain_master_stage2(struct subnet_record *subrec, 
77                                         struct userdata_struct *userdata,
78                                         struct nmb_name *registered_name,
79                                         uint16 nb_flags,
80                                         int ttl, struct in_addr registered_ip)
81 {
82   struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
83   struct server_record *servrec;
84
85   if(!work)
86   {
87     DEBUG(0,("become_domain_master_stage2: Error - cannot find \
88 workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
89     return;
90   }
91
92   if((servrec = find_server_in_workgroup( work, lp_netbios_name())) == NULL)
93   {
94     DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
95 in workgroup %s on subnet %s\n", 
96              lp_netbios_name(), registered_name->name, 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     {
112     dbgtext( "*****\n\nSamba server %s ", lp_netbios_name() );
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   {
120     struct nmb_name nmbname;
121     struct in_addr my_first_ip;
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, lp_netbios_name(), 0x20);
129
130     work->dmb_name = nmbname;
131     /* Pick the first interface ip address as the domain master browser ip. */
132     my_first_ip = *iface_n_ip(0);
133
134     putip((char *)&work->dmb_addr, &my_first_ip);
135
136     /* We successfully registered by unicast with the
137        WINS server.  We now expect to become the domain
138        master on the local subnets. If this fails, it's
139        probably a 1.9.16p2 to 1.9.16p11 server's fault.
140
141        This is a configuration issue that should be addressed
142        by the network administrator - you shouldn't have
143        several machines configured as a domain master browser
144        for the same WINS scope (except if they are 1.9.17 or
145        greater, and you know what you're doing.
146
147        see docs/DOMAIN.txt.
148
149      */
150     become_domain_master_browser_bcast(work->work_group);
151   }
152   else
153   {
154     /*
155      * Now we are a domain master on a broadcast subnet, we need to add
156      * the WORKGROUP<1b> name to the unicast subnet so that we can answer
157      * unicast requests sent to this name. This bug wasn't found for a while
158      * as it is strange to have a DMB without using WINS. JRA.
159      */
160     insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
161   }
162 }
163
164 /****************************************************************************
165   Start the name registration process when becoming a Domain Master Browser
166   on a subnet.
167   ****************************************************************************/
168
169 static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name)
170
171   struct work_record *work;
172
173   DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
174 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
175
176   /* First, find the workgroup on the subnet. */
177   if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL)
178   {
179     DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
180           wg_name, subrec->subnet_name));
181     return;
182   }
183
184   DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
185   work->dom_state = DOMAIN_WAIT;
186
187   /* WORKGROUP<1b> is the domain master browser name. */
188   register_name(subrec, work->work_group,0x1b,samba_nb_type,
189                 become_domain_master_stage2,
190                 become_domain_master_fail, NULL);
191 }
192
193 /****************************************************************************
194   Function called when a query for a WORKGROUP<1b> name succeeds.
195   This is normally a fail condition as it means there is already
196   a domain master browser for a workgroup and we were trying to
197   become one.
198 ****************************************************************************/
199
200 static void become_domain_master_query_success(struct subnet_record *subrec,
201                         struct userdata_struct *userdata,
202                         struct nmb_name *nmbname, struct in_addr ip, 
203                         struct res_rec *rrec)
204 {
205   /* If the given ip is not ours, then we can't become a domain
206      controler as the name is already registered.
207    */
208
209  /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
210     address or zero ip for this query. Pretend this is ok. */
211
212   if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip))
213   {
214     if( DEBUGLVL( 3 ) )
215     {
216       dbgtext( "become_domain_master_query_success():\n" );
217       dbgtext( "Our address (%s) ", inet_ntoa(ip) );
218       dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
219       dbgtext( "(domain master browser name) " );
220       dbgtext( "on subnet %s.\n", subrec->subnet_name );
221       dbgtext( "Continuing with domain master code.\n" );
222     }
223
224     become_domain_master_stage1(subrec, nmbname->name);
225   }
226   else
227   {
228     if( DEBUGLVL( 0 ) )
229       {
230       dbgtext( "become_domain_master_query_success:\n" );
231       dbgtext( "There is already a domain master browser at " );
232       dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), nmbname->name );
233       dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
234       }
235   }
236 }
237
238 /****************************************************************************
239   Function called when a query for a WORKGROUP<1b> name fails.
240   This is normally a success condition as it then allows us to register
241   our own Domain Master Browser name.
242   ****************************************************************************/
243
244 static void become_domain_master_query_fail(struct subnet_record *subrec,
245                                     struct response_record *rrec,
246                                     struct nmb_name *question_name, int fail_code)
247 {
248   /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
249      then this is a failure. Otherwise, not finding the name is what we want. */
250   if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
251   {
252     DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
253 querying WINS server for name %s.\n", 
254                   fail_code, nmb_namestr(question_name)));
255     return;
256   }
257
258   /* Otherwise - not having the name allows us to register it. */
259   become_domain_master_stage1(subrec, question_name->name);
260 }
261
262 /****************************************************************************
263   Attempt to become a domain master browser on all broadcast subnets.
264   ****************************************************************************/
265
266 static void become_domain_master_browser_bcast(const char *workgroup_name)
267 {
268   struct subnet_record *subrec;
269
270   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
271   { 
272     struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
273
274     if (work && (work->dom_state == DOMAIN_NONE))
275     {
276       struct nmb_name nmbname;
277       make_nmb_name(&nmbname,workgroup_name,0x1b);
278
279       /*
280        * Check for our name on the given broadcast subnet first, only initiate
281        * further processing if we cannot find it.
282        */
283
284       if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
285       {
286         if( DEBUGLVL( 0 ) )
287           {
288           dbgtext( "become_domain_master_browser_bcast:\n" );
289           dbgtext( "Attempting to become domain master browser on " );
290           dbgtext( "workgroup %s on subnet %s\n",
291                     workgroup_name, subrec->subnet_name );
292           }
293
294         /* Send out a query to establish whether there's a 
295            domain controller on the local subnet. If not,
296            we can become a domain controller. 
297          */
298
299         DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
300 for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
301
302         query_name(subrec, nmbname.name, nmbname.name_type,
303                    become_domain_master_query_success, 
304                    become_domain_master_query_fail,
305                    NULL);
306       }
307     }
308   }
309 }
310
311 /****************************************************************************
312   Attempt to become a domain master browser by registering with WINS.
313   ****************************************************************************/
314
315 static void become_domain_master_browser_wins(const char *workgroup_name)
316 {
317   struct work_record *work;
318
319   work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
320
321   if (work && (work->dom_state == DOMAIN_NONE))
322   {
323     struct nmb_name nmbname;
324
325     make_nmb_name(&nmbname,workgroup_name,0x1b);
326
327     /*
328      * Check for our name on the unicast subnet first, only initiate
329      * further processing if we cannot find it.
330      */
331
332     if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
333     {
334       if( DEBUGLVL( 0 ) )
335         {
336         dbgtext( "become_domain_master_browser_wins:\n" );
337         dbgtext( "Attempting to become domain master browser " );
338         dbgtext( "on workgroup %s, subnet %s.\n",
339                   workgroup_name, unicast_subnet->subnet_name );
340         }
341
342       /* Send out a query to establish whether there's a 
343          domain master broswer registered with WINS. If not,
344          we can become a domain master browser. 
345        */
346
347       DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
348 for domain master browser name %s on workgroup %s\n",
349          inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
350
351       query_name(unicast_subnet, nmbname.name, nmbname.name_type,
352                    become_domain_master_query_success,
353                    become_domain_master_query_fail,
354                    NULL);
355     }
356   }
357 }
358
359 /****************************************************************************
360   Add the domain logon server and domain master browser names
361   if we are set up to do so.
362   **************************************************************************/
363
364 void add_domain_names(time_t t)
365 {
366   static time_t lastrun = 0;
367
368   if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
369     return;
370
371   lastrun = t;
372
373   /* Do the "internet group" - <1c> names. */
374   if (lp_domain_logons())
375     add_logon_names();
376
377   /* Do the domain master names. */
378   if(lp_server_role() == ROLE_DOMAIN_PDC)
379   {
380     if(we_are_a_wins_client())
381     {
382       /* We register the WORKGROUP<1b> name with the WINS
383          server first, and call add_domain_master_bcast()
384          only if this is successful.
385
386          This results in domain logon services being gracefully provided,
387          as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
388          1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
389          cannot provide domain master / domain logon services.
390        */
391       become_domain_master_browser_wins(lp_workgroup());
392     }
393     else
394       become_domain_master_browser_bcast(lp_workgroup());
395   }
396 }