This looks like a big change but really isn't.
[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 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   Unbecome a domain master browser - name release success function.
42   ******************************************************************/
43
44 static void unbecome_dmb_success(struct subnet_record *subrec,
45                                  struct userdata_struct *userdata,
46                                  struct nmb_name *released_name,
47                                  struct in_addr released_ip)
48 {
49   struct work_record *work = find_workgroup_on_subnet(subrec, released_name->name);
50   struct server_record *servrec;
51
52   if(!work)
53   {
54     DEBUG(0,("unbecome_dmb_success: Cannot find workgroup %s on subnet %s\n",
55              released_name->name, subrec->subnet_name));
56     return;
57   }
58
59   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
60   {
61     DEBUG(0,("unbecome_dmb_success: Error - cannot find server %s \
62 in workgroup %s on subnet %s\n",
63        global_myname, released_name->name, subrec->subnet_name));
64     return;
65   }
66
67   /* Set the state in the workgroup structure. */
68   work->dom_state = DOMAIN_NONE;
69
70   /* Update our server status. */
71   servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
72
73   /* Tell the namelist writer to write out a change. */
74   subrec->work_changed = True;
75
76   /* Remove any list of local master browsers we are syncing with. */
77   remove_workgroup_lmb_browsers(released_name->name);
78
79   /* Delete the known domain master browser name from the workgroup
80      struct. */
81   bzero((char *)&work->dmb_name, sizeof(work->dmb_name));
82   putip((char *)&work->dmb_addr, &ipzero);
83
84   DEBUG(0,("\n%s ***** Samba server %s has stopped being a domain master browser \
85 for workgroup %s on subnet %s *****\n\n", timestring(), global_myname, work->work_group, subrec->subnet_name));
86
87 }
88
89 /*******************************************************************
90   Unbecome a domain master browser - name release fail function.
91   ******************************************************************/
92
93 static void unbecome_dmb_fail(struct subnet_record *subrec,
94                                  struct response_record *rrec,
95                                  struct nmb_name *released_name)
96 {
97   DEBUG(0,("unbecome_dmb_fail: Failed to unbecome domain master browser for \
98 workgroup %s on subnet %s.\n", released_name->name, subrec->subnet_name));
99 }
100
101 /*******************************************************************
102   Unbecome a domain master browser.
103   ******************************************************************/
104
105 void unbecome_domain_master(char *workgroup_name)
106 {   
107   struct subnet_record *subrec;
108
109   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
110   {
111     struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
112
113     if(work && (work->dom_state == DOMAIN_MST))
114     {
115       struct name_record *namerec;
116       struct nmb_name nmbname;
117       make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
118
119       /* We can only do this if we are a domain master already. */
120       DEBUG(2,("unbecome_domain_master: attempting to stop being a domain \
121 master browser for workgroup %s on subnet %s\n",
122               work->work_group, subrec->subnet_name));
123    
124       /* Find the WORKGROUP<1b> name on the subnet namelist. */
125       if((namerec = find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME))==NULL)
126       {
127         DEBUG(0,("unbecome_domain_master: Cannot find name %s on subnet %s.\n",
128                 namestr(&nmbname), subrec->subnet_name));
129         continue;
130       }
131       release_name(subrec, namerec, 
132                    unbecome_dmb_success,
133                    unbecome_dmb_fail,
134                    NULL);
135     }
136   }
137
138
139 /****************************************************************************
140   Fail to become a Domain Master Browser on a subnet.
141   ****************************************************************************/
142
143 static void become_domain_master_fail(struct subnet_record *subrec,
144                                       struct response_record *rrec,
145                                       struct nmb_name *fail_name)
146 {
147   struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
148   struct server_record *servrec;
149
150   if(!work)
151   {
152     DEBUG(0,("become_domain_master_fail: Error - cannot find \
153 workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
154     return;
155   }
156
157   /* Set the state back to DOMAIN_NONE. */
158   work->dom_state = DOMAIN_NONE;
159
160   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
161   {
162     DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
163 in workgroup %s on subnet %s\n",
164        global_myname, work->work_group, subrec->subnet_name));
165     return;
166   }
167
168   /* Update our server status. */
169   servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
170
171   /* Tell the namelist writer to write out a change. */
172   subrec->work_changed = True;
173
174   DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
175 workgroup %s on subnet %s. Couldn't register name %s.\n",
176        work->work_group, subrec->subnet_name, namestr(fail_name)));
177 }
178
179 /****************************************************************************
180   Become a Domain Master Browser on a subnet.
181   ****************************************************************************/
182
183 static void become_domain_master_stage2(struct subnet_record *subrec, 
184                                         struct userdata_struct *userdata,
185                                         struct nmb_name *registered_name,
186                                         uint16 nb_flags,
187                                         int ttl, struct in_addr registered_ip)
188 {
189   struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
190   struct server_record *servrec;
191
192   if(!work)
193   {
194     DEBUG(0,("become_domain_master_stage2: Error - cannot find \
195 workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
196     return;
197   }
198
199   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
200   {
201     DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
202 in workgroup %s on subnet %s\n", 
203        global_myname, registered_name->name, subrec->subnet_name));
204     work->dom_state = DOMAIN_NONE;
205     return;
206   }
207
208   /* Set the state in the workgroup structure. */
209   work->dom_state = DOMAIN_MST; /* Become domain master. */
210
211   /* Update our server status. */
212   servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
213
214   /* Tell the namelist writer to write out a change. */
215   subrec->work_changed = True;
216
217   DEBUG(0,("\n%s ***** Samba server %s is now a domain master browser for \
218 workgroup %s on subnet %s *****\n\n", timestring(),global_myname, work->work_group, 
219 subrec->subnet_name));
220
221   if(subrec == unicast_subnet)
222   {
223     struct nmb_name nmbname;
224     struct in_addr my_first_ip;
225
226     /* Put our name and first IP address into the 
227        workgroup struct as domain master browser. This
228        will stop us syncing with ourself if we are also
229        a local master browser. */
230
231     make_nmb_name(&nmbname, global_myname, 0x20, scope);
232
233     work->dmb_name = nmbname;
234     /* Pick the first interface ip address as the domain master browser ip. */
235     my_first_ip = *iface_n_ip(0);
236
237     putip((char *)&work->dmb_addr, &my_first_ip);
238
239     /* We successfully registered by unicast with the
240        WINS server.  We now expect to become the domain
241        master on the local subnets. If this fails, it's
242        probably a 1.9.16p2 to 1.9.16p11 server's fault.
243
244        This is a configuration issue that should be addressed
245        by the network administrator - you shouldn't have
246        several machines configured as a domain master browser
247        for the same WINS scope (except if they are 1.9.17 or
248        greater, and you know what you're doing.
249
250        see docs/DOMAIN.txt.
251
252      */
253     become_domain_master_browser_bcast(work->work_group);
254   }
255 }
256
257 /****************************************************************************
258   Start the name registration process when becoming a Domain Master Browser
259   on a subnet.
260   ****************************************************************************/
261
262 static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name)
263
264   struct work_record *work;
265
266   DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
267 workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
268
269   /* First, find the workgroup on the subnet. */
270   if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL)
271   {
272     DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
273           wg_name, subrec->subnet_name));
274     return;
275   }
276
277   DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
278   work->dom_state = DOMAIN_WAIT;
279
280   /* WORKGROUP<1b> is the domain master browser name. */
281   register_name(subrec, work->work_group,0x1b,samba_nb_type,
282                 become_domain_master_stage2,
283                 become_domain_master_fail, NULL);
284 }
285
286 /****************************************************************************
287   Function called when a query for a WORKGROUP<1b> name succeeds.
288   This is normally a fail condition as it means there is already
289   a domain master browser for a workgroup and we were trying to
290   become one.
291 ****************************************************************************/
292
293 static void become_domain_master_query_success(struct subnet_record *subrec,
294                         struct userdata_struct *userdata,
295                         struct nmb_name *nmbname, struct in_addr ip, 
296                         struct res_rec *rrec)
297 {
298   /* If the given ip is not ours, then we can't become a domain
299      controler as the name is already registered.
300    */
301
302  /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
303     address or zero ip for this query. Pretend this is ok. */
304
305   if(ismyip(ip) || ip_equal(allones_ip, ip) || ip_equal(ipzero, ip))
306   {
307     DEBUG(3,("become_domain_master_query_success: Our address (%s) returned \
308 in query for name %s (domain master browser name) on subnet %s. \
309 Continuing with domain master code.\n", 
310            inet_ntoa(ip), namestr(nmbname), subrec->subnet_name));
311
312     become_domain_master_stage1(subrec, nmbname->name);
313   }
314   else
315   {
316     DEBUG(0,("%s become_domain_master_query_success: There is already a domain \
317 master browser at IP %s for workgroup %s registered on subnet %s.\n",
318           timestring(), inet_ntoa(ip), nmbname->name, subrec->subnet_name));
319   }
320 }
321
322 /****************************************************************************
323   Function called when a query for a WORKGROUP<1b> name fails.
324   This is normally a success condition as it then allows us to register
325   our own Domain Master Browser name.
326   ****************************************************************************/
327
328 static void become_domain_master_query_fail(struct subnet_record *subrec,
329                                     struct response_record *rrec,
330                                     struct nmb_name *question_name, int fail_code)
331 {
332   /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
333      then this is a failure. Otherwise, not finding the name is what we want. */
334   if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
335   {
336     DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
337 querying WINS server for name %s.\n", 
338                   fail_code, namestr(question_name)));
339     return;
340   }
341
342   /* Otherwise - not having the name allows us to register it. */
343   become_domain_master_stage1(subrec, question_name->name);
344 }
345
346 /****************************************************************************
347   Attempt to become a domain master browser on all broadcast subnets.
348   ****************************************************************************/
349
350 static void become_domain_master_browser_bcast(char *workgroup_name)
351 {
352   struct subnet_record *subrec;
353
354   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
355   { 
356     struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
357
358     if (work && (work->dom_state == DOMAIN_NONE))
359     {
360       struct nmb_name nmbname;
361       make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
362
363       /*
364        * Check for our name on the given broadcast subnet first, only initiate
365        * further processing if we cannot find it.
366        */
367
368       if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
369       {
370         DEBUG(0,("become_domain_master_browser_bcast: At time %s attempting to become domain \
371 master browser on workgroup %s on subnet %s\n", timestring(), 
372                  workgroup_name, subrec->subnet_name));
373
374         /* Send out a query to establish whether there's a 
375            domain controller on the local subnet. If not,
376            we can become a domain controller. 
377          */
378
379         DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
380 for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
381
382         query_name(subrec, nmbname.name, nmbname.name_type,
383                    become_domain_master_query_success, 
384                    become_domain_master_query_fail,
385                    NULL);
386       }
387     }
388   }
389 }
390
391 /****************************************************************************
392   Attempt to become a domain master browser by registering with WINS.
393   ****************************************************************************/
394
395 static void become_domain_master_browser_wins(char *workgroup_name)
396 {
397   struct work_record *work;
398
399   work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
400
401   if (work && (work->dom_state == DOMAIN_NONE))
402   {
403     struct nmb_name nmbname;
404
405     make_nmb_name(&nmbname,workgroup_name,0x1b,scope);
406
407     /*
408      * Check for our name on the unicast subnet first, only initiate
409      * further processing if we cannot find it.
410      */
411
412     if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
413     {
414       DEBUG(0,("%s become_domain_master_browser_wins: attempting to become domain \
415 master browser on workgroup %s, subnet %s.\n",
416       timestring(), workgroup_name, unicast_subnet->subnet_name));
417
418       /* Send out a query to establish whether there's a 
419          domain master broswer registered with WINS. If not,
420          we can become a domain master browser. 
421        */
422
423       DEBUG(0,("become_domain_master_browser_wins: querying WINS server at IP %s \
424 for domain master browser name %s on workgroup %s\n",
425          inet_ntoa(unicast_subnet->myip), namestr(&nmbname), workgroup_name));
426
427       query_name(unicast_subnet, nmbname.name, nmbname.name_type,
428                    become_domain_master_query_success,
429                    become_domain_master_query_fail,
430                    NULL);
431     }
432   }
433 }
434
435 /****************************************************************************
436   Add the domain logon server and domain master browser names
437   if we are set up to do so.
438   **************************************************************************/
439
440 void add_domain_names(time_t t)
441 {
442   static time_t lastrun = 0;
443
444   if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
445     return;
446
447   lastrun = t;
448
449   /* Do the "internet group" - <1c> names. */
450   if (lp_domain_logons())
451     add_logon_names();
452
453   /* Do the domain master names. */
454   if(lp_domain_master())
455   {
456     if(we_are_a_wins_client())
457     {
458       /* We register the WORKGROUP<1b> name with the WINS
459          server first, and call add_domain_master_bcast()
460          only if this is successful.
461
462          This results in domain logon services being gracefully provided,
463          as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
464          1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
465          cannot provide domain master / domain logon services.
466        */
467       become_domain_master_browser_wins(global_myworkgroup);
468     }
469     else
470       become_domain_master_browser_bcast(global_myworkgroup);
471   }
472 }