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