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