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