r8839: adding patches from Marcin. Have to still work on
[Samba.git] / source / nsswitch / winbindd_misc.c
blob6f72a0e2c63f69de88fe2311e2ba124177e464d2
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon - miscellaneous other functions
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Bartlett 2002
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.
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.
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.
24 #include "includes.h"
25 #include "winbindd.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_WINBIND
30 /* Check the machine account password is valid */
32 void winbindd_check_machine_acct(struct winbindd_cli_state *state)
34 DEBUG(3, ("[%5lu]: check machine account\n",
35 (unsigned long)state->pid));
37 sendto_domain(state, find_our_domain());
40 enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
41 struct winbindd_cli_state *state)
43 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
44 int num_retries = 0;
45 struct winbindd_domain *contact_domain;
47 DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
49 /* Get trust account password */
51 again:
53 contact_domain = find_our_domain();
55 /* This call does a cli_nt_setup_creds() which implicitly checks
56 the trust account password. */
58 invalidate_cm_connection(&contact_domain->conn);
61 struct rpc_pipe_client *cli;
62 unsigned char *session_key;
63 DOM_CRED *creds;
65 result = cm_connect_netlogon(contact_domain, state->mem_ctx,
66 &cli, &session_key, &creds);
69 if (!NT_STATUS_IS_OK(result)) {
70 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
71 goto done;
74 /* There is a race condition between fetching the trust account
75 password and the periodic machine password change. So it's
76 possible that the trust account password has been changed on us.
77 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
79 #define MAX_RETRIES 8
81 if ((num_retries < MAX_RETRIES) &&
82 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
83 num_retries++;
84 goto again;
87 /* Pass back result code - zero for success, other values for
88 specific failures. */
90 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
91 "good" : "bad"));
93 done:
94 state->response.data.auth.nt_status = NT_STATUS_V(result);
95 fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
96 fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
97 state->response.data.auth.pam_error = nt_status_to_pam(result);
99 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
100 state->response.data.auth.nt_status_string));
102 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
105 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
107 DEBUG(3, ("[%5lu]: list trusted domains\n",
108 (unsigned long)state->pid));
110 sendto_domain(state, find_our_domain());
113 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
114 struct winbindd_cli_state *state)
116 uint32 i, num_domains;
117 char **names, **alt_names;
118 DOM_SID *sids;
119 int extra_data_len = 0;
120 char *extra_data;
121 NTSTATUS result;
123 DEBUG(3, ("[%5lu]: list trusted domains\n",
124 (unsigned long)state->pid));
126 result = domain->methods->trusted_domains(domain, state->mem_ctx,
127 &num_domains, &names,
128 &alt_names, &sids);
130 extra_data = talloc_strdup(state->mem_ctx, "");
132 if (num_domains > 0)
133 extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
134 names[0], alt_names[0],
135 sid_string_static(&sids[0]));
137 for (i=1; i<num_domains; i++)
138 extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
139 extra_data,
140 names[i], alt_names[i],
141 sid_string_static(&sids[i]));
143 /* This is a bit excessive, but the extra data sooner or later will be
144 talloc'ed */
146 extra_data_len = strlen(extra_data);
148 if (extra_data_len > 0) {
149 state->response.extra_data = SMB_STRDUP(extra_data);
150 state->response.length += extra_data_len+1;
153 return WINBINDD_OK;
156 void winbindd_getdcname(struct winbindd_cli_state *state)
158 state->request.domain_name
159 [sizeof(state->request.domain_name)-1] = '\0';
161 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
162 state->request.domain_name));
164 sendto_domain(state, find_our_domain());
167 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
168 struct winbindd_cli_state *state)
170 fstring dcname_slash;
171 char *p;
172 struct rpc_pipe_client *cli;
173 NTSTATUS result;
175 state->request.domain_name
176 [sizeof(state->request.domain_name)-1] = '\0';
178 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
179 state->request.domain_name));
182 /* These var's can be ignored -- we're not requesting
183 anything in the credential chain here */
184 unsigned char *session_key;
185 DOM_CRED *creds;
186 result = cm_connect_netlogon(domain, state->mem_ctx, &cli,
187 &session_key, &creds);
190 if (!NT_STATUS_IS_OK(result)) {
191 DEBUG(1, ("Can't contact our the NETLOGON pipe\n"));
192 return WINBINDD_ERROR;
195 result = rpccli_netlogon_getdcname(cli, state->mem_ctx, domain->dcname,
196 state->request.domain_name,
197 dcname_slash);
199 if (!NT_STATUS_IS_OK(result)) {
200 DEBUG(5, ("Error requesting DCname: %s\n", nt_errstr(result)));
201 return WINBINDD_ERROR;
204 p = dcname_slash;
205 if (*p == '\\') p+=1;
206 if (*p == '\\') p+=1;
208 fstrcpy(state->response.data.dc_name, p);
210 return WINBINDD_OK;
213 struct sequence_state {
214 TALLOC_CTX *mem_ctx;
215 struct winbindd_cli_state *cli_state;
216 struct winbindd_domain *domain;
217 struct winbindd_request *request;
218 struct winbindd_response *response;
219 char *extra_data;
222 static void sequence_recv(void *private_data, BOOL success);
224 void winbindd_show_sequence(struct winbindd_cli_state *state)
226 struct sequence_state *seq;
228 /* Ensure null termination */
229 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
231 if (strlen(state->request.domain_name) > 0) {
232 struct winbindd_domain *domain;
233 domain = find_domain_from_name_noinit(
234 state->request.domain_name);
235 if (domain == NULL) {
236 request_error(state);
237 return;
239 sendto_domain(state, domain);
240 return;
243 /* Ask all domains in sequence, collect the results in sequence_recv */
245 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
246 if (seq == NULL) {
247 DEBUG(0, ("talloc failed\n"));
248 request_error(state);
249 return;
252 seq->mem_ctx = state->mem_ctx;
253 seq->cli_state = state;
254 seq->domain = domain_list();
255 if (seq->domain == NULL) {
256 DEBUG(0, ("domain list empty\n"));
257 request_error(state);
258 return;
260 seq->request = TALLOC_ZERO_P(state->mem_ctx,
261 struct winbindd_request);
262 seq->response = TALLOC_ZERO_P(state->mem_ctx,
263 struct winbindd_response);
264 seq->extra_data = talloc_strdup(state->mem_ctx, "");
266 if ((seq->request == NULL) || (seq->response == NULL) ||
267 (seq->extra_data == NULL)) {
268 DEBUG(0, ("talloc failed\n"));
269 request_error(state);
270 return;
273 seq->request->length = sizeof(*seq->request);
274 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
275 fstrcpy(seq->request->domain_name, seq->domain->name);
277 async_domain_request(state->mem_ctx, seq->domain,
278 seq->request, seq->response,
279 sequence_recv, seq);
282 static void sequence_recv(void *private_data, BOOL success)
284 struct sequence_state *state = private_data;
285 uint32 seq = DOM_SEQUENCE_NONE;
287 if ((success) && (state->response->result == WINBINDD_OK))
288 seq = state->response->data.domain_info.sequence_number;
290 if (seq == DOM_SEQUENCE_NONE) {
291 state->extra_data = talloc_asprintf(state->mem_ctx,
292 "%s%s : DISCONNECTED\n",
293 state->extra_data,
294 state->domain->name);
295 } else {
296 state->extra_data = talloc_asprintf(state->mem_ctx,
297 "%s%s : %d\n",
298 state->extra_data,
299 state->domain->name, seq);
302 state->domain->sequence_number = seq;
304 state->domain = state->domain->next;
306 if (state->domain == NULL) {
307 struct winbindd_cli_state *cli_state = state->cli_state;
308 cli_state->response.length =
309 sizeof(cli_state->response) +
310 strlen(state->extra_data) + 1;
311 cli_state->response.extra_data =
312 SMB_STRDUP(state->extra_data);
313 request_ok(cli_state);
314 return;
317 /* Ask the next domain */
318 fstrcpy(state->request->domain_name, state->domain->name);
319 async_domain_request(state->mem_ctx, state->domain,
320 state->request, state->response,
321 sequence_recv, state);
324 /* This is the child-only version of --sequence. It only allows for a single
325 * domain (ie "our" one) to be displayed. */
327 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
328 struct winbindd_cli_state *state)
330 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
332 /* Ensure null termination */
333 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
335 domain->methods->sequence_number(domain, &domain->sequence_number);
337 state->response.data.domain_info.sequence_number =
338 domain->sequence_number;
340 return WINBINDD_OK;
343 struct domain_info_state {
344 struct winbindd_domain *domain;
345 struct winbindd_cli_state *cli_state;
348 static void domain_info_init_recv(void *private_data, BOOL success);
350 void winbindd_domain_info(struct winbindd_cli_state *state)
352 struct winbindd_domain *domain;
354 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
355 state->request.domain_name));
357 domain = find_domain_from_name_noinit(state->request.domain_name);
359 if (domain == NULL) {
360 DEBUG(3, ("Did not find domain [%s]\n",
361 state->request.domain_name));
362 request_error(state);
363 return;
366 if (!domain->initialized) {
367 struct domain_info_state *istate;
369 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
370 if (istate == NULL) {
371 DEBUG(0, ("talloc failed\n"));
372 request_error(state);
373 return;
376 istate->cli_state = state;
377 istate->domain = domain;
379 init_child_connection(domain, domain_info_init_recv, istate);
381 return;
384 fstrcpy(state->response.data.domain_info.name,
385 domain->name);
386 fstrcpy(state->response.data.domain_info.alt_name,
387 domain->alt_name);
388 fstrcpy(state->response.data.domain_info.sid,
389 sid_string_static(&domain->sid));
391 state->response.data.domain_info.native_mode =
392 domain->native_mode;
393 state->response.data.domain_info.active_directory =
394 domain->active_directory;
395 state->response.data.domain_info.primary =
396 domain->primary;
397 state->response.data.domain_info.sequence_number =
398 domain->sequence_number;
400 request_ok(state);
403 static void domain_info_init_recv(void *private_data, BOOL success)
405 struct domain_info_state *istate = private_data;
406 struct winbindd_cli_state *state = istate->cli_state;
407 struct winbindd_domain *domain = istate->domain;
409 DEBUG(10, ("Got back from child init: %d\n", success));
411 if ((!success) || (!domain->initialized)) {
412 DEBUG(5, ("Could not init child for domain %s\n",
413 domain->name));
414 request_error(state);
415 return;
418 fstrcpy(state->response.data.domain_info.name,
419 domain->name);
420 fstrcpy(state->response.data.domain_info.alt_name,
421 domain->alt_name);
422 fstrcpy(state->response.data.domain_info.sid,
423 sid_string_static(&domain->sid));
425 state->response.data.domain_info.native_mode =
426 domain->native_mode;
427 state->response.data.domain_info.active_directory =
428 domain->active_directory;
429 state->response.data.domain_info.primary =
430 domain->primary;
431 state->response.data.domain_info.sequence_number =
432 domain->sequence_number;
434 request_ok(state);
437 void winbindd_ping(struct winbindd_cli_state *state)
439 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
440 request_ok(state);
443 /* List various tidbits of information */
445 void winbindd_info(struct winbindd_cli_state *state)
448 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
450 state->response.data.info.winbind_separator = *lp_winbind_separator();
451 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
452 request_ok(state);
455 /* Tell the client the current interface version */
457 void winbindd_interface_version(struct winbindd_cli_state *state)
459 DEBUG(3, ("[%5lu]: request interface version\n",
460 (unsigned long)state->pid));
462 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
463 request_ok(state);
466 /* What domain are we a member of? */
468 void winbindd_domain_name(struct winbindd_cli_state *state)
470 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
472 fstrcpy(state->response.data.domain_name, lp_workgroup());
473 request_ok(state);
476 /* What's my name again? */
478 void winbindd_netbios_name(struct winbindd_cli_state *state)
480 DEBUG(3, ("[%5lu]: request netbios name\n",
481 (unsigned long)state->pid));
483 fstrcpy(state->response.data.netbios_name, global_myname());
484 request_ok(state);
487 /* Where can I find the privilaged pipe? */
489 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
492 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
493 (unsigned long)state->pid));
495 state->response.extra_data = SMB_STRDUP(get_winbind_priv_pipe_dir());
496 if (!state->response.extra_data) {
497 DEBUG(0, ("malloc failed\n"));
498 request_error(state);
499 return;
502 /* must add one to length to copy the 0 for string termination */
503 state->response.length +=
504 strlen((char *)state->response.extra_data) + 1;
506 request_ok(state);