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
32enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state)
33{
34	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
35	uchar trust_passwd[16];
36        int num_retries = 0;
37        struct cli_state *cli;
38	uint32 sec_channel_type;
39	struct winbindd_domain *contact_domain;
40
41	DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
42
43	/* Get trust account password */
44
45 again:
46	if (!secrets_fetch_trust_account_password(
47		    lp_workgroup(), trust_passwd, NULL, &sec_channel_type)) {
48		result = NT_STATUS_INTERNAL_ERROR;
49		goto done;
50	}
51
52
53	contact_domain = find_our_domain();
54        if (!contact_domain) {
55		result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
56                DEBUG(1, ("Cannot find our own domain!\n"));
57                goto done;
58        }
59
60        /* This call does a cli_nt_setup_creds() which implicitly checks
61           the trust account password. */
62	/* Don't shut this down - it belongs to the connection cache code */
63
64        result = cm_get_netlogon_cli(contact_domain,
65		trust_passwd, sec_channel_type, True, &cli);
66
67        if (!NT_STATUS_IS_OK(result)) {
68                DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
69                goto done;
70        }
71
72        /* There is a race condition between fetching the trust account
73           password and the periodic machine password change.  So it's
74	   possible that the trust account password has been changed on us.
75	   We are returned NT_STATUS_ACCESS_DENIED if this happens. */
76
77#define MAX_RETRIES 8
78
79        if ((num_retries < MAX_RETRIES) &&
80            NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
81                num_retries++;
82                goto again;
83        }
84
85	/* Pass back result code - zero for success, other values for
86	   specific failures. */
87
88	DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
89                  "good" : "bad"));
90
91 done:
92	state->response.data.auth.nt_status = NT_STATUS_V(result);
93	fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
94	fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
95	state->response.data.auth.pam_error = nt_status_to_pam(result);
96
97	DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
98						state->response.data.auth.nt_status_string));
99
100	return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
101}
102
103enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
104						   *state)
105{
106	struct winbindd_domain *domain;
107	int total_entries = 0, extra_data_len = 0;
108	char *ted, *extra_data = NULL;
109
110	DEBUG(3, ("[%5lu]: list trusted domains\n", (unsigned long)state->pid));
111
112	/* We need to refresh the trusted domain list as the domains may
113	   have changed since we last looked.  There may be a sequence
114	   number or something we should use but I haven't found it yet. */
115
116	if (!init_domain_list()) {
117		DEBUG(1, ("winbindd_list_trusted_domains: could not "
118			  "refresh trusted domain list\n"));
119		return WINBINDD_ERROR;
120	}
121
122	for(domain = domain_list(); domain; domain = domain->next) {
123
124		/* Skip own domain */
125
126		if (domain->primary) continue;
127
128		/* Add domain to list */
129
130		total_entries++;
131		ted = SMB_REALLOC(extra_data, sizeof(fstring) *
132                              total_entries);
133
134		if (!ted) {
135			DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n"));
136			SAFE_FREE(extra_data);
137			return WINBINDD_ERROR;
138		} else
139                        extra_data = ted;
140
141		memcpy(&extra_data[extra_data_len], domain->name,
142		       strlen(domain->name));
143
144		extra_data_len  += strlen(domain->name);
145		extra_data[extra_data_len++] = ',';
146	}
147
148	if (extra_data) {
149		if (extra_data_len > 1)
150                        extra_data[extra_data_len - 1] = '\0';
151		state->response.extra_data = extra_data;
152		state->response.length += extra_data_len;
153	}
154
155	return WINBINDD_OK;
156}
157
158
159enum winbindd_result winbindd_show_sequence(struct winbindd_cli_state *state)
160{
161	struct winbindd_domain *domain;
162	char *extra_data = NULL;
163	const char *which_domain;
164
165	DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
166
167	/* Ensure null termination */
168	state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
169	which_domain = state->request.domain_name;
170
171	extra_data = SMB_STRDUP("");
172
173	/* this makes for a very simple data format, and is easily parsable as well
174	   if that is ever needed */
175	for (domain = domain_list(); domain; domain = domain->next) {
176		char *s;
177
178		/* if we have a domain name restricting the request and this
179		   one in the list doesn't match, then just bypass the remainder
180		   of the loop */
181
182		if ( *which_domain && !strequal(which_domain, domain->name) )
183			continue;
184
185		domain->methods->sequence_number(domain, &domain->sequence_number);
186
187		if (DOM_SEQUENCE_NONE == (unsigned)domain->sequence_number) {
188			asprintf(&s,"%s%s : DISCONNECTED\n", extra_data,
189				 domain->name);
190		} else {
191			asprintf(&s,"%s%s : %u\n", extra_data,
192				 domain->name, (unsigned)domain->sequence_number);
193		}
194		free(extra_data);
195		extra_data = s;
196	}
197
198	state->response.extra_data = extra_data;
199	/* must add one to length to copy the 0 for string termination */
200	state->response.length += strlen(extra_data) + 1;
201
202	return WINBINDD_OK;
203}
204
205enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
206{
207	struct winbindd_domain *domain;
208
209	DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
210		  state->request.domain_name));
211
212	domain = find_domain_from_name(state->request.domain_name);
213
214	if (domain == NULL) {
215		DEBUG(3, ("Did not find domain [%s]\n",
216			  state->request.domain_name));
217		return WINBINDD_ERROR;
218	}
219
220	fstrcpy(state->response.data.domain_info.name, domain->name);
221	fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
222	fstrcpy(state->response.data.domain_info.sid,
223		sid_string_static(&domain->sid));
224
225	state->response.data.domain_info.native_mode = domain->native_mode;
226	state->response.data.domain_info.active_directory = domain->active_directory;
227	state->response.data.domain_info.primary = domain->primary;
228
229	state->response.data.domain_info.sequence_number =
230		domain->sequence_number;
231
232	return WINBINDD_OK;
233}
234
235enum winbindd_result winbindd_ping(struct winbindd_cli_state
236						   *state)
237{
238	DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
239
240	return WINBINDD_OK;
241}
242
243/* List various tidbits of information */
244
245enum winbindd_result winbindd_info(struct winbindd_cli_state *state)
246{
247
248	DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
249
250	state->response.data.info.winbind_separator = *lp_winbind_separator();
251	fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
252
253	return WINBINDD_OK;
254}
255
256/* Tell the client the current interface version */
257
258enum winbindd_result winbindd_interface_version(struct winbindd_cli_state *state)
259{
260
261	DEBUG(3, ("[%5lu]: request interface version\n", (unsigned long)state->pid));
262
263	state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
264
265	return WINBINDD_OK;
266}
267
268/* What domain are we a member of? */
269
270enum winbindd_result winbindd_domain_name(struct winbindd_cli_state *state)
271{
272
273	DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
274
275	fstrcpy(state->response.data.domain_name, lp_workgroup());
276
277	return WINBINDD_OK;
278}
279
280/* What's my name again? */
281
282enum winbindd_result winbindd_netbios_name(struct winbindd_cli_state *state)
283{
284
285	DEBUG(3, ("[%5lu]: request netbios name\n", (unsigned long)state->pid));
286
287	fstrcpy(state->response.data.netbios_name, global_myname());
288
289	return WINBINDD_OK;
290}
291
292/* Where can I find the privilaged pipe? */
293
294enum winbindd_result winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
295{
296
297	DEBUG(3, ("[%5lu]: request location of privileged pipe\n", (unsigned long)state->pid));
298
299	state->response.extra_data = SMB_STRDUP(get_winbind_priv_pipe_dir());
300	if (!state->response.extra_data)
301		return WINBINDD_ERROR;
302
303	/* must add one to length to copy the 0 for string termination */
304	state->response.length += strlen((char *)state->response.extra_data) + 1;
305
306	return WINBINDD_OK;
307}
308