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
26extern struct in_addr allones_ip;
27
28extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
29
30static void become_domain_master_browser_bcast(const char *);
31
32/****************************************************************************
33  Fail to become a Domain Master Browser on a subnet.
34  ****************************************************************************/
35
36static 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 \
48workgroup %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 \
57in 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 \
69workgroup %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
77static 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 \
92workgroup %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 \
98in 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
168static 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 \
173workgroup %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
198static 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
240static 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 \
251querying 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
265static 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 \
295for 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
310static 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 \
340for 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
356void 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}
387