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