• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.0.25b/source/nsswitch/
1/*
2   Unix SMB/CIFS implementation.
3
4   Winbind daemon - miscellaneous other functions
5
6   Copyright (C) Tim Potter      2000
7   Copyright (C) Andrew Bartlett 2002
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#include "includes.h"
25#include "winbindd.h"
26
27#undef DBGC_CLASS
28#define DBGC_CLASS DBGC_WINBIND
29
30/* Check the machine account password is valid */
31
32void winbindd_check_machine_acct(struct winbindd_cli_state *state)
33{
34	DEBUG(3, ("[%5lu]: check machine account\n",
35		  (unsigned long)state->pid));
36
37	sendto_domain(state, find_our_domain());
38}
39
40enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
41						      struct winbindd_cli_state *state)
42{
43	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
44        int num_retries = 0;
45	struct winbindd_domain *contact_domain;
46
47	DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
48
49	/* Get trust account password */
50
51 again:
52
53	contact_domain = find_our_domain();
54
55        /* This call does a cli_nt_setup_creds() which implicitly checks
56           the trust account password. */
57
58	invalidate_cm_connection(&contact_domain->conn);
59
60	{
61		struct rpc_pipe_client *netlogon_pipe;
62		result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
63	}
64
65        if (!NT_STATUS_IS_OK(result)) {
66                DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
67                goto done;
68        }
69
70        /* There is a race condition between fetching the trust account
71           password and the periodic machine password change.  So it's
72	   possible that the trust account password has been changed on us.
73	   We are returned NT_STATUS_ACCESS_DENIED if this happens. */
74
75#define MAX_RETRIES 8
76
77        if ((num_retries < MAX_RETRIES) &&
78            NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
79                num_retries++;
80                goto again;
81        }
82
83	/* Pass back result code - zero for success, other values for
84	   specific failures. */
85
86	DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
87                  "good" : "bad"));
88
89 done:
90	state->response.data.auth.nt_status = NT_STATUS_V(result);
91	fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
92	fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
93	state->response.data.auth.pam_error = nt_status_to_pam(result);
94
95	DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
96						state->response.data.auth.nt_status_string));
97
98	return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
99}
100
101void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
102{
103	DEBUG(3, ("[%5lu]: list trusted domains\n",
104		  (unsigned long)state->pid));
105
106	sendto_domain(state, find_our_domain());
107}
108
109enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
110							struct winbindd_cli_state *state)
111{
112	uint32 i, num_domains;
113	char **names, **alt_names;
114	DOM_SID *sids;
115	int extra_data_len = 0;
116	char *extra_data;
117	NTSTATUS result;
118	BOOL have_own_domain = False;
119
120	DEBUG(3, ("[%5lu]: list trusted domains\n",
121		  (unsigned long)state->pid));
122
123	result = domain->methods->trusted_domains(domain, state->mem_ctx,
124						  &num_domains, &names,
125						  &alt_names, &sids);
126
127	if (!NT_STATUS_IS_OK(result)) {
128		DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
129			nt_errstr(result) ));
130		return WINBINDD_ERROR;
131	}
132
133	extra_data = talloc_strdup(state->mem_ctx, "");
134
135	if (num_domains > 0)
136		extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
137					     names[0],
138					     alt_names[0] ? alt_names[0] : names[0],
139					     sid_string_static(&sids[0]));
140
141	for (i=1; i<num_domains; i++)
142		extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
143					     extra_data,
144					     names[i],
145					     alt_names[i] ? alt_names[i] : names[i],
146					     sid_string_static(&sids[i]));
147	/* add our primary domain */
148
149	for (i=0; i<num_domains; i++) {
150		if (strequal(names[i], domain->name)) {
151			have_own_domain = True;
152			break;
153		}
154	}
155
156	if (state->request.data.list_all_domains && !have_own_domain) {
157		extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
158					     extra_data,
159					     domain->name,
160					     domain->alt_name ? domain->alt_name : domain->name,
161					     sid_string_static(&domain->sid));
162	}
163
164	/* This is a bit excessive, but the extra data sooner or later will be
165	   talloc'ed */
166
167	extra_data_len = 0;
168	if (extra_data != NULL) {
169		extra_data_len = strlen(extra_data);
170	}
171
172	if (extra_data_len > 0) {
173		state->response.extra_data.data = SMB_STRDUP(extra_data);
174		state->response.length += extra_data_len+1;
175	}
176
177	return WINBINDD_OK;
178}
179
180void winbindd_getdcname(struct winbindd_cli_state *state)
181{
182	state->request.domain_name
183		[sizeof(state->request.domain_name)-1] = '\0';
184
185	DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
186		  state->request.domain_name));
187
188	sendto_domain(state, find_our_domain());
189}
190
191enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
192					     struct winbindd_cli_state *state)
193{
194	fstring dcname_slash;
195	char *p;
196	struct rpc_pipe_client *netlogon_pipe;
197	NTSTATUS result;
198	WERROR werr;
199	unsigned int orig_timeout;
200
201	state->request.domain_name
202		[sizeof(state->request.domain_name)-1] = '\0';
203
204	DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
205		  state->request.domain_name));
206
207	result = cm_connect_netlogon(domain, &netlogon_pipe);
208
209	if (!NT_STATUS_IS_OK(result)) {
210		DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
211		return WINBINDD_ERROR;
212	}
213
214	/* This call can take a long time - allow the server to time out.
215	   35 seconds should do it. */
216
217	orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
218
219	werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx, domain->dcname,
220					    state->request.domain_name,
221					    dcname_slash);
222	/* And restore our original timeout. */
223	cli_set_timeout(netlogon_pipe->cli, orig_timeout);
224
225	if (!W_ERROR_IS_OK(werr)) {
226		DEBUG(5, ("Error requesting DCname: %s\n", dos_errstr(werr)));
227		return WINBINDD_ERROR;
228	}
229
230	p = dcname_slash;
231	if (*p == '\\') {
232		p+=1;
233	}
234	if (*p == '\\') {
235		p+=1;
236	}
237
238	fstrcpy(state->response.data.dc_name, p);
239	return WINBINDD_OK;
240}
241
242struct sequence_state {
243	TALLOC_CTX *mem_ctx;
244	struct winbindd_cli_state *cli_state;
245	struct winbindd_domain *domain;
246	struct winbindd_request *request;
247	struct winbindd_response *response;
248	char *extra_data;
249};
250
251static void sequence_recv(void *private_data, BOOL success);
252
253void winbindd_show_sequence(struct winbindd_cli_state *state)
254{
255	struct sequence_state *seq;
256
257	/* Ensure null termination */
258	state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
259
260	if (strlen(state->request.domain_name) > 0) {
261		struct winbindd_domain *domain;
262		domain = find_domain_from_name_noinit(
263			state->request.domain_name);
264		if (domain == NULL) {
265			request_error(state);
266			return;
267		}
268		sendto_domain(state, domain);
269		return;
270	}
271
272	/* Ask all domains in sequence, collect the results in sequence_recv */
273
274	seq = TALLOC_P(state->mem_ctx, struct sequence_state);
275	if (seq == NULL) {
276		DEBUG(0, ("talloc failed\n"));
277		request_error(state);
278		return;
279	}
280
281	seq->mem_ctx = state->mem_ctx;
282	seq->cli_state = state;
283	seq->domain = domain_list();
284	if (seq->domain == NULL) {
285		DEBUG(0, ("domain list empty\n"));
286		request_error(state);
287		return;
288	}
289	seq->request = TALLOC_ZERO_P(state->mem_ctx,
290				     struct winbindd_request);
291	seq->response = TALLOC_ZERO_P(state->mem_ctx,
292				      struct winbindd_response);
293	seq->extra_data = talloc_strdup(state->mem_ctx, "");
294
295	if ((seq->request == NULL) || (seq->response == NULL) ||
296	    (seq->extra_data == NULL)) {
297		DEBUG(0, ("talloc failed\n"));
298		request_error(state);
299		return;
300	}
301
302	seq->request->length = sizeof(*seq->request);
303	seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
304	fstrcpy(seq->request->domain_name, seq->domain->name);
305
306	async_domain_request(state->mem_ctx, seq->domain,
307			     seq->request, seq->response,
308			     sequence_recv, seq);
309}
310
311static void sequence_recv(void *private_data, BOOL success)
312{
313	struct sequence_state *state =
314		(struct sequence_state *)private_data;
315	uint32 seq = DOM_SEQUENCE_NONE;
316
317	if ((success) && (state->response->result == WINBINDD_OK))
318		seq = state->response->data.domain_info.sequence_number;
319
320	if (seq == DOM_SEQUENCE_NONE) {
321		state->extra_data = talloc_asprintf(state->mem_ctx,
322						    "%s%s : DISCONNECTED\n",
323						    state->extra_data,
324						    state->domain->name);
325	} else {
326		state->extra_data = talloc_asprintf(state->mem_ctx,
327						    "%s%s : %d\n",
328						    state->extra_data,
329						    state->domain->name, seq);
330	}
331
332	state->domain->sequence_number = seq;
333
334	state->domain = state->domain->next;
335
336	if (state->domain == NULL) {
337		struct winbindd_cli_state *cli_state = state->cli_state;
338		cli_state->response.length =
339			sizeof(cli_state->response) +
340			strlen(state->extra_data) + 1;
341		cli_state->response.extra_data.data =
342			SMB_STRDUP(state->extra_data);
343		request_ok(cli_state);
344		return;
345	}
346
347	/* Ask the next domain */
348	fstrcpy(state->request->domain_name, state->domain->name);
349	async_domain_request(state->mem_ctx, state->domain,
350			     state->request, state->response,
351			     sequence_recv, state);
352}
353
354/* This is the child-only version of --sequence. It only allows for a single
355 * domain (ie "our" one) to be displayed. */
356
357enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
358						 struct winbindd_cli_state *state)
359{
360	DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
361
362	/* Ensure null termination */
363	state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
364
365	domain->methods->sequence_number(domain, &domain->sequence_number);
366
367	state->response.data.domain_info.sequence_number =
368		domain->sequence_number;
369
370	return WINBINDD_OK;
371}
372
373struct domain_info_state {
374	struct winbindd_domain *domain;
375	struct winbindd_cli_state *cli_state;
376};
377
378static void domain_info_init_recv(void *private_data, BOOL success);
379
380void winbindd_domain_info(struct winbindd_cli_state *state)
381{
382	struct winbindd_domain *domain;
383
384	DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
385		  state->request.domain_name));
386
387	domain = find_domain_from_name_noinit(state->request.domain_name);
388
389	if (domain == NULL) {
390		DEBUG(3, ("Did not find domain [%s]\n",
391			  state->request.domain_name));
392		request_error(state);
393		return;
394	}
395
396	if (!domain->initialized) {
397		struct domain_info_state *istate;
398
399		istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
400		if (istate == NULL) {
401			DEBUG(0, ("talloc failed\n"));
402			request_error(state);
403			return;
404		}
405
406		istate->cli_state = state;
407		istate->domain = domain;
408
409		init_child_connection(domain, domain_info_init_recv, istate);
410
411		return;
412	}
413
414	fstrcpy(state->response.data.domain_info.name,
415		domain->name);
416	fstrcpy(state->response.data.domain_info.alt_name,
417		domain->alt_name);
418	fstrcpy(state->response.data.domain_info.sid,
419		sid_string_static(&domain->sid));
420
421	state->response.data.domain_info.native_mode =
422		domain->native_mode;
423	state->response.data.domain_info.active_directory =
424		domain->active_directory;
425	state->response.data.domain_info.primary =
426		domain->primary;
427	state->response.data.domain_info.sequence_number =
428		domain->sequence_number;
429
430	request_ok(state);
431}
432
433static void domain_info_init_recv(void *private_data, BOOL success)
434{
435	struct domain_info_state *istate =
436		(struct domain_info_state *)private_data;
437	struct winbindd_cli_state *state = istate->cli_state;
438	struct winbindd_domain *domain = istate->domain;
439
440	DEBUG(10, ("Got back from child init: %d\n", success));
441
442	if ((!success) || (!domain->initialized)) {
443		DEBUG(5, ("Could not init child for domain %s\n",
444			  domain->name));
445		request_error(state);
446		return;
447	}
448
449	fstrcpy(state->response.data.domain_info.name,
450		domain->name);
451	fstrcpy(state->response.data.domain_info.alt_name,
452		domain->alt_name);
453	fstrcpy(state->response.data.domain_info.sid,
454		sid_string_static(&domain->sid));
455
456	state->response.data.domain_info.native_mode =
457		domain->native_mode;
458	state->response.data.domain_info.active_directory =
459		domain->active_directory;
460	state->response.data.domain_info.primary =
461		domain->primary;
462	state->response.data.domain_info.sequence_number =
463		domain->sequence_number;
464
465	request_ok(state);
466}
467
468void winbindd_ping(struct winbindd_cli_state *state)
469{
470	DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
471	request_ok(state);
472}
473
474/* List various tidbits of information */
475
476void winbindd_info(struct winbindd_cli_state *state)
477{
478
479	DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
480
481	state->response.data.info.winbind_separator = *lp_winbind_separator();
482	fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
483	request_ok(state);
484}
485
486/* Tell the client the current interface version */
487
488void winbindd_interface_version(struct winbindd_cli_state *state)
489{
490	DEBUG(3, ("[%5lu]: request interface version\n",
491		  (unsigned long)state->pid));
492
493	state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
494	request_ok(state);
495}
496
497/* What domain are we a member of? */
498
499void winbindd_domain_name(struct winbindd_cli_state *state)
500{
501	DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
502
503	fstrcpy(state->response.data.domain_name, lp_workgroup());
504	request_ok(state);
505}
506
507/* What's my name again? */
508
509void winbindd_netbios_name(struct winbindd_cli_state *state)
510{
511	DEBUG(3, ("[%5lu]: request netbios name\n",
512		  (unsigned long)state->pid));
513
514	fstrcpy(state->response.data.netbios_name, global_myname());
515	request_ok(state);
516}
517
518/* Where can I find the privilaged pipe? */
519
520void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
521{
522
523	DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
524		  (unsigned long)state->pid));
525
526	state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
527	if (!state->response.extra_data.data) {
528		DEBUG(0, ("malloc failed\n"));
529		request_error(state);
530		return;
531	}
532
533	/* must add one to length to copy the 0 for string termination */
534	state->response.length +=
535		strlen((char *)state->response.extra_data.data) + 1;
536
537	request_ok(state);
538}
539