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