first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[nivanova/samba-autobuild/.git] / source3 / nmbd / nmbd_become_dmb.c
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
8    
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.
13    
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.
18    
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.
22    
23 */
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28
29 extern pstring scope;
30 extern pstring global_myname;
31 extern fstring global_myworkgroup;
32 extern char **my_netbios_names;
33 extern struct in_addr ipzero;
34 extern struct in_addr allones_ip;
35
36 extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
37
38 static void become_domain_master_browser_bcast(char *);
39
40 /****************************************************************************
41   Fail to become a Domain Master Browser on a subnet.
42   ****************************************************************************/
43
44 static void become_domain_master_fail(struct subnet_record *subrec,
45                                       struct response_record *rrec,
46                                       struct nmb_name *fail_name)
47 {
48   struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
49   struct server_record *servrec;
50
51   if(!work)
52   {
53     DEBUG(0,("become_domain_master_fail: Error - cannot find \
54 workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
55     return;
56   }
57
58   /* Set the state back to DOMAIN_NONE. */
59   work->dom_state = DOMAIN_NONE;
60
61   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
62   {
63     DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
64 in workgroup %s on subnet %s\n",
65        global_myname, work->work_group, subrec->subnet_name));
66     return;
67   }
68
69   /* Update our server status. */
70   servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
71
72   /* Tell the namelist writer to write out a change. */
73   subrec->work_changed = True;
74
75   DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
76 workgroup %s on subnet %s. Couldn't register name %s.\n",
77        work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
78 }
79
80 /****************************************************************************
81   Become a Domain Master Browser on a subnet.
82   ****************************************************************************/
83
84 static void become_domain_master_stage2(struct subnet_record *subrec, 
85                                         struct userdata_struct *userdata,
86                                         struct nmb_name *registered_name,
87                                         uint16 nb_flags,
88                                         int ttl, struct in_addr registered_ip)
89 {
90   struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
91   struct server_record *servrec;
92
93   if(!work)
94   {
95     DEBUG(0,("become_domain_master_stage2: Error - cannot find \
96 workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
97     return;
98   }
99
100   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
101   {
102     DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
103 in workgroup %s on subnet %s\n", 
104        global_myname, registered_name->name, subrec->subnet_name));
105     work->dom_state = DOMAIN_NONE;
106     return;
107   }
108
109   /* Set the state in the workgroup structure. */
110   work->dom_state = DOMAIN_MST; /* Become domain master. */
111
112   /* Update our server status. */
113   servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
114
115   /* Tell the namelist writer to write out a change. */
116   subrec->work_changed = True;
117
118   if( DEBUGLVL( 0 ) )
119     {
120     dbgtext( "*****\n\nSamba server %s ", global_myname );
121     dbgtext( "is now a domain master browser for " );
122     dbgtext( "workgroup %s ", work->work_group );
123     dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
124     }
125
126   if( subrec == unicast_subnet )
127   {
128     struct nmb_name nmbname;
129     struct in_addr my_first_ip;
130
131     /* Put our name and first IP address into the 
132        workgroup struct as domain master browser. This
133        will stop us syncing with ourself if we are also
134        a local master browser. */
135
136     make_nmb_name(&nmbname, global_myname, 0x20, scope);
137
138     work->dmb_name = nmbname;
139     /* Pick the first interface ip address as the domain master browser ip. */
140     my_first_ip = *iface_n_ip(0);
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   }
160   else
161   {
162     /*
163      * Now we are a domain master on a broadcast subnet, we need to add
164      * the WORKGROUP<1b> name to the unicast subnet so that we can answer
165      * unicast requests sent to this name. This bug wasn't found for a while
166      * as it is strange to have a DMB without using WINS. JRA.
167      */
168     insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
169   }
170 }
171
172 /****************************************************************************
173   Start the name registration process when becoming a Domain Master Browser
174   on a subnet.
175   ****************************************************************************/
176
177 static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name)
178
179   struct work_record *work;
180
181   DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
182 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
183
184   /* First, find the workgroup on the subnet. */
185   if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL)
186   {
187     DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
188           wg_name, subrec->subnet_name));
189     return;
190   }
191
192   DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
193   work->dom_state = DOMAIN_WAIT;
194
195   /* WORKGROUP<1b> is the domain master browser name. */
196   register_name(subrec, work->work_group,0x1b,samba_nb_type,
197                 become_domain_master_stage2,
198                 become_domain_master_fail, NULL);
199 }
200
201 /****************************************************************************
202   Function called when a query for a WORKGROUP<1b> name succeeds.
203   This is normally a fail condition as it means there is already
204   a domain master browser for a workgroup and we were trying to
205   become one.
206 ****************************************************************************/
207
208 static void become_domain_master_query_success(struct subnet_record *subrec,
209                         struct userdata_struct *userdata,
210                         struct nmb_name *nmbname, struct in_addr ip, 
211                         struct res_rec *rrec)
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   if(ismyip(ip) || ip_equal(allones_ip, ip) || ip_equal(ipzero, ip))
221   {
222     if( DEBUGLVL( 3 ) )
223     {
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, nmbname->name);
233   }
234   else
235   {
236     if( DEBUGLVL( 0 ) )
237       {
238       dbgtext( "become_domain_master_query_success:\n" );
239       dbgtext( "There is already a domain master browser at " );
240       dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), nmbname->name );
241       dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
242       }
243   }
244 }
245
246 /****************************************************************************
247   Function called when a query for a WORKGROUP<1b> name fails.
248   This is normally a success condition as it then allows us to register
249   our own Domain Master Browser name.
250   ****************************************************************************/
251
252 static void become_domain_master_query_fail(struct subnet_record *subrec,
253                                     struct response_record *rrec,
254                                     struct nmb_name *question_name, int fail_code)
255 {
256   /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
257      then this is a failure. Otherwise, not finding the name is what we want. */
258   if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
259   {
260     DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
261 querying WINS server for name %s.\n", 
262                   fail_code, nmb_namestr(question_name)));
263     return;
264   }
265
266   /* Otherwise - not having the name allows us to register it. */
267   become_domain_master_stage1(subrec, question_name->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(char *workgroup_name)
275 {
276   struct subnet_record *subrec;
277
278   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
279   { 
280     struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
281
282     if (work && (work->dom_state == DOMAIN_NONE))
283     {
284       struct nmb_name nmbname;
285       make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
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       {
294         if( DEBUGLVL( 0 ) )
295           {
296           dbgtext( "become_domain_master_browser_bcast:\n" );
297           dbgtext( "Attempting to become domain master browser on " );
298           dbgtext( "workgroup %s on subnet %s\n",
299                     workgroup_name, subrec->subnet_name );
300           }
301
302         /* Send out a query to establish whether there's a 
303            domain controller on the local subnet. If not,
304            we can become a domain controller. 
305          */
306
307         DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
308 for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
309
310         query_name(subrec, nmbname.name, nmbname.name_type,
311                    become_domain_master_query_success, 
312                    become_domain_master_query_fail,
313                    NULL);
314       }
315     }
316   }
317 }
318
319 /****************************************************************************
320   Attempt to become a domain master browser by registering with WINS.
321   ****************************************************************************/
322
323 static void become_domain_master_browser_wins(char *workgroup_name)
324 {
325   struct work_record *work;
326
327   work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
328
329   if (work && (work->dom_state == DOMAIN_NONE))
330   {
331     struct nmb_name nmbname;
332
333     make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
334
335     /*
336      * Check for our name on the unicast subnet first, only initiate
337      * further processing if we cannot find it.
338      */
339
340     if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
341     {
342       if( DEBUGLVL( 0 ) )
343         {
344         dbgtext( "become_domain_master_browser_wins:\n" );
345         dbgtext( "Attempting to become domain master browser " );
346         dbgtext( "on workgroup %s, subnet %s.\n",
347                   workgroup_name, unicast_subnet->subnet_name );
348         }
349
350       /* Send out a query to establish whether there's a 
351          domain master broswer registered with WINS. If not,
352          we can become a domain master browser. 
353        */
354
355       DEBUG(0,("become_domain_master_browser_wins: querying WINS server at IP %s \
356 for domain master browser name %s on workgroup %s\n",
357          inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
358
359       query_name(unicast_subnet, nmbname.name, nmbname.name_type,
360                    become_domain_master_query_success,
361                    become_domain_master_query_fail,
362                    NULL);
363     }
364   }
365 }
366
367 /****************************************************************************
368   Add the domain logon server and domain master browser names
369   if we are set up to do so.
370   **************************************************************************/
371
372 void add_domain_names(time_t t)
373 {
374   static time_t lastrun = 0;
375
376   if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
377     return;
378
379   lastrun = t;
380
381   /* Do the "internet group" - <1c> names. */
382   if (lp_domain_logons())
383     add_logon_names();
384
385   /* Do the domain master names. */
386   if(lp_domain_master())
387   {
388     if(we_are_a_wins_client())
389     {
390       /* We register the WORKGROUP<1b> name with the WINS
391          server first, and call add_domain_master_bcast()
392          only if this is successful.
393
394          This results in domain logon services being gracefully provided,
395          as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
396          1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
397          cannot provide domain master / domain logon services.
398        */
399       become_domain_master_browser_wins(global_myworkgroup);
400     }
401     else
402       become_domain_master_browser_bcast(global_myworkgroup);
403   }
404 }