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