r7415: * big change -- volker's new async winbindd from trunk
[Samba/gbeck.git] / source / nsswitch / winbindd_misc.c
blob9cfa4c6fcc4eeb9c53401a63255609e4fa745fdf
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 enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state)
34 DEBUG(3, ("[%5lu]: check machine account\n",
35 (unsigned long)state->pid));
37 async_domain_request(state->mem_ctx, find_our_domain(),
38 &state->request, &state->response,
39 request_finished_cont, state);
40 return WINBINDD_PENDING;
43 enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
44 struct winbindd_cli_state *state)
46 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
47 int num_retries = 0;
48 struct winbindd_domain *contact_domain;
50 DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
52 /* Get trust account password */
54 again:
56 contact_domain = find_our_domain();
58 /* This call does a cli_nt_setup_creds() which implicitly checks
59 the trust account password. */
61 invalidate_cm_connection(&contact_domain->conn);
64 struct rpc_pipe_client *cli;
65 unsigned char *session_key;
66 DOM_CRED *creds;
68 result = cm_connect_netlogon(contact_domain, state->mem_ctx,
69 &cli, &session_key, &creds);
72 if (!NT_STATUS_IS_OK(result)) {
73 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
74 goto done;
77 /* There is a race condition between fetching the trust account
78 password and the periodic machine password change. So it's
79 possible that the trust account password has been changed on us.
80 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
82 #define MAX_RETRIES 8
84 if ((num_retries < MAX_RETRIES) &&
85 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
86 num_retries++;
87 goto again;
90 /* Pass back result code - zero for success, other values for
91 specific failures. */
93 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
94 "good" : "bad"));
96 done:
97 state->response.data.auth.nt_status = NT_STATUS_V(result);
98 fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
99 fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
100 state->response.data.auth.pam_error = nt_status_to_pam(result);
102 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
103 state->response.data.auth.nt_status_string));
105 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
108 enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state *state)
110 DEBUG(3, ("[%5lu]: list trusted domains\n",
111 (unsigned long)state->pid));
113 async_domain_request(state->mem_ctx, find_our_domain(),
114 &state->request, &state->response,
115 request_finished_cont, state);
116 return WINBINDD_PENDING;
119 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
120 struct winbindd_cli_state *state)
122 uint32 i, num_domains;
123 char **names, **alt_names;
124 DOM_SID *sids;
125 int extra_data_len = 0;
126 char *extra_data;
127 NTSTATUS result;
129 DEBUG(3, ("[%5lu]: list trusted domains\n",
130 (unsigned long)state->pid));
132 result = domain->methods->trusted_domains(domain, state->mem_ctx,
133 &num_domains, &names,
134 &alt_names, &sids);
136 extra_data = talloc_strdup(state->mem_ctx, "");
138 if (num_domains > 0)
139 extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
140 names[0], alt_names[0],
141 sid_string_static(&sids[0]));
143 for (i=1; i<num_domains; i++)
144 extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
145 extra_data,
146 names[i], alt_names[i],
147 sid_string_static(&sids[i]));
149 /* This is a bit excessive, but the extra data sooner or later will be
150 talloc'ed */
152 extra_data_len = strlen(extra_data);
154 if (extra_data_len > 0) {
155 state->response.extra_data = SMB_STRDUP(extra_data);
156 state->response.length += extra_data_len+1;
159 return WINBINDD_OK;
162 enum winbindd_result winbindd_getdcname(struct winbindd_cli_state *state)
164 state->request.domain_name
165 [sizeof(state->request.domain_name)-1] = '\0';
167 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
168 state->request.domain_name));
170 async_domain_request(state->mem_ctx, find_our_domain(),
171 &state->request, &state->response,
172 request_finished_cont, state);
173 return WINBINDD_PENDING;
176 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
177 struct winbindd_cli_state *state)
179 fstring dcname_slash;
180 char *p;
181 struct rpc_pipe_client *cli;
182 NTSTATUS result;
184 state->request.domain_name
185 [sizeof(state->request.domain_name)-1] = '\0';
187 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
188 state->request.domain_name));
191 /* These var's can be ignored -- we're not requesting
192 anything in the credential chain here */
193 unsigned char *session_key;
194 DOM_CRED *creds;
195 result = cm_connect_netlogon(domain, state->mem_ctx, &cli,
196 &session_key, &creds);
199 if (!NT_STATUS_IS_OK(result)) {
200 DEBUG(1, ("Can't contact our the NETLOGON pipe\n"));
201 return WINBINDD_ERROR;
204 result = rpccli_netlogon_getdcname(cli, state->mem_ctx, domain->dcname,
205 state->request.domain_name,
206 dcname_slash);
208 if (!NT_STATUS_IS_OK(result)) {
209 DEBUG(5, ("Error requesting DCname: %s\n", nt_errstr(result)));
210 return WINBINDD_ERROR;
213 p = dcname_slash;
214 if (*p == '\\') p+=1;
215 if (*p == '\\') p+=1;
217 fstrcpy(state->response.data.dc_name, p);
219 return WINBINDD_OK;
222 struct sequence_state {
223 TALLOC_CTX *mem_ctx;
224 struct winbindd_cli_state *cli_state;
225 struct winbindd_domain *domain;
226 struct winbindd_request *request;
227 struct winbindd_response *response;
228 char *extra_data;
231 static void sequence_recv(void *private, BOOL success);
233 enum winbindd_result winbindd_show_sequence(struct winbindd_cli_state *state)
235 struct sequence_state *seq;
237 /* Ensure null termination */
238 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
240 if (strlen(state->request.domain_name) > 0) {
241 struct winbindd_domain *domain;
242 domain = find_domain_from_name_noinit(
243 state->request.domain_name);
244 if (domain == NULL)
245 return WINBINDD_ERROR;
246 async_domain_request(state->mem_ctx, domain,
247 &state->request, &state->response,
248 request_finished_cont, state);
249 return WINBINDD_PENDING;
252 /* Ask all domains in sequence, collect the results in sequence_recv */
254 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
255 if (seq == NULL) {
256 DEBUG(0, ("talloc failed\n"));
257 return WINBINDD_ERROR;
260 seq->mem_ctx = state->mem_ctx;
261 seq->cli_state = state;
262 seq->domain = domain_list();
263 if (seq->domain == NULL) {
264 DEBUG(0, ("domain list empty\n"));
265 return WINBINDD_ERROR;
267 seq->request = TALLOC_ZERO_P(state->mem_ctx,
268 struct winbindd_request);
269 seq->response = TALLOC_ZERO_P(state->mem_ctx,
270 struct winbindd_response);
271 seq->extra_data = talloc_strdup(state->mem_ctx, "");
273 if ((seq->request == NULL) || (seq->response == NULL) ||
274 (seq->extra_data == NULL)) {
275 DEBUG(0, ("talloc failed\n"));
276 return WINBINDD_ERROR;
279 seq->request->length = sizeof(*seq->request);
280 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
281 fstrcpy(seq->request->domain_name, seq->domain->name);
283 async_domain_request(state->mem_ctx, seq->domain,
284 seq->request, seq->response,
285 sequence_recv, seq);
286 return WINBINDD_PENDING;
289 static void sequence_recv(void *private, BOOL success)
291 struct sequence_state *state = private;
292 uint32 seq = DOM_SEQUENCE_NONE;
294 if ((success) && (state->response->result == WINBINDD_OK))
295 seq = state->response->data.domain_info.sequence_number;
297 if (seq == DOM_SEQUENCE_NONE) {
298 state->extra_data = talloc_asprintf(state->mem_ctx,
299 "%s%s : DISCONNECTED\n",
300 state->extra_data,
301 state->domain->name);
302 } else {
303 state->extra_data = talloc_asprintf(state->mem_ctx,
304 "%s%s : %d\n",
305 state->extra_data,
306 state->domain->name, seq);
309 state->domain->sequence_number = seq;
311 state->domain = state->domain->next;
313 if (state->domain == NULL) {
314 struct winbindd_cli_state *cli_state = state->cli_state;
315 cli_state->response.result = WINBINDD_OK;
316 cli_state->response.length =
317 sizeof(cli_state->response) +
318 strlen(state->extra_data) + 1;
319 cli_state->response.extra_data =
320 SMB_STRDUP(state->extra_data);
321 request_finished(cli_state);
322 return;
325 /* Ask the next domain */
326 fstrcpy(state->request->domain_name, state->domain->name);
327 async_domain_request(state->mem_ctx, state->domain,
328 state->request, state->response,
329 sequence_recv, state);
332 /* This is the child-only version of --sequence. It only allows for a single
333 * domain (ie "our" one) to be displayed. */
335 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
336 struct winbindd_cli_state *state)
338 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
340 /* Ensure null termination */
341 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
343 domain->methods->sequence_number(domain, &domain->sequence_number);
345 state->response.data.domain_info.sequence_number =
346 domain->sequence_number;
348 return WINBINDD_OK;
351 struct domain_info_state {
352 struct winbindd_domain *domain;
353 struct winbindd_cli_state *cli_state;
356 static void domain_info_init_recv(void *private, BOOL success);
358 enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state)
360 struct winbindd_domain *domain;
362 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
363 state->request.domain_name));
365 domain = find_domain_from_name_noinit(state->request.domain_name);
367 if (domain == NULL) {
368 DEBUG(3, ("Did not find domain [%s]\n",
369 state->request.domain_name));
370 return WINBINDD_ERROR;
373 if (!domain->initialized) {
374 struct domain_info_state *istate;
376 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
377 if (istate == NULL) {
378 DEBUG(0, ("talloc failed\n"));
379 return WINBINDD_ERROR;
382 istate->cli_state = state;
383 istate->domain = domain;
385 init_child_connection(domain, domain_info_init_recv, istate);
387 return WINBINDD_PENDING;
390 fstrcpy(state->response.data.domain_info.name,
391 domain->name);
392 fstrcpy(state->response.data.domain_info.alt_name,
393 domain->alt_name);
394 fstrcpy(state->response.data.domain_info.sid,
395 sid_string_static(&domain->sid));
397 state->response.data.domain_info.native_mode =
398 domain->native_mode;
399 state->response.data.domain_info.active_directory =
400 domain->active_directory;
401 state->response.data.domain_info.primary =
402 domain->primary;
403 state->response.data.domain_info.sequence_number =
404 domain->sequence_number;
406 return WINBINDD_OK;
409 static void domain_info_init_recv(void *private, BOOL success)
411 struct domain_info_state *istate = private;
412 struct winbindd_cli_state *state = istate->cli_state;
413 struct winbindd_domain *domain = istate->domain;
415 DEBUG(10, ("Got back from child init: %d\n", success));
417 if ((!success) || (!domain->initialized)) {
418 DEBUG(5, ("Could not init child for domain %s\n",
419 domain->name));
420 state->response.result = WINBINDD_ERROR;
421 request_finished_cont(state, False);
422 return;
425 fstrcpy(state->response.data.domain_info.name,
426 domain->name);
427 fstrcpy(state->response.data.domain_info.alt_name,
428 domain->alt_name);
429 fstrcpy(state->response.data.domain_info.sid,
430 sid_string_static(&domain->sid));
432 state->response.data.domain_info.native_mode =
433 domain->native_mode;
434 state->response.data.domain_info.active_directory =
435 domain->active_directory;
436 state->response.data.domain_info.primary =
437 domain->primary;
438 state->response.data.domain_info.sequence_number =
439 domain->sequence_number;
441 state->response.result = WINBINDD_OK;
442 request_finished_cont(state, True);
445 enum winbindd_result winbindd_ping(struct winbindd_cli_state
446 *state)
448 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
450 return WINBINDD_OK;
453 /* List various tidbits of information */
455 enum winbindd_result winbindd_info(struct winbindd_cli_state *state)
458 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
460 state->response.data.info.winbind_separator = *lp_winbind_separator();
461 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
463 return WINBINDD_OK;
466 /* Tell the client the current interface version */
468 enum winbindd_result winbindd_interface_version(struct winbindd_cli_state *state)
471 DEBUG(3, ("[%5lu]: request interface version\n", (unsigned long)state->pid));
473 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
475 return WINBINDD_OK;
478 /* What domain are we a member of? */
480 enum winbindd_result winbindd_domain_name(struct winbindd_cli_state *state)
483 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
485 fstrcpy(state->response.data.domain_name, lp_workgroup());
487 return WINBINDD_OK;
490 /* What's my name again? */
492 enum winbindd_result winbindd_netbios_name(struct winbindd_cli_state *state)
495 DEBUG(3, ("[%5lu]: request netbios name\n", (unsigned long)state->pid));
497 fstrcpy(state->response.data.netbios_name, global_myname());
499 return WINBINDD_OK;
502 /* Where can I find the privilaged pipe? */
504 enum winbindd_result winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
507 DEBUG(3, ("[%5lu]: request location of privileged pipe\n", (unsigned long)state->pid));
509 state->response.extra_data = SMB_STRDUP(get_winbind_priv_pipe_dir());
510 if (!state->response.extra_data)
511 return WINBINDD_ERROR;
513 /* must add one to length to copy the 0 for string termination */
514 state->response.length += strlen((char *)state->response.extra_data) + 1;
516 return WINBINDD_OK;