r19143: getdcname on the NETLOGON pipe returns WERROR, not NTSTATUS.
[Samba/bb.git] / source3 / nsswitch / winbindd_misc.c
blob34ce468516119d66596e7fbefdfe4d45036e94d4
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 *netlogon_pipe;
62 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
65 if (!NT_STATUS_IS_OK(result)) {
66 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
67 goto done;
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. */
75 #define MAX_RETRIES 8
77 if ((num_retries < MAX_RETRIES) &&
78 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
79 num_retries++;
80 goto again;
83 /* Pass back result code - zero for success, other values for
84 specific failures. */
86 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
87 "good" : "bad"));
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);
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));
98 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
101 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
103 DEBUG(3, ("[%5lu]: list trusted domains\n",
104 (unsigned long)state->pid));
106 sendto_domain(state, find_our_domain());
109 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
110 struct winbindd_cli_state *state)
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;
120 DEBUG(3, ("[%5lu]: list trusted domains\n",
121 (unsigned long)state->pid));
123 result = domain->methods->trusted_domains(domain, state->mem_ctx,
124 &num_domains, &names,
125 &alt_names, &sids);
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 num_domains = 0;
133 extra_data = talloc_strdup(state->mem_ctx, "");
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]));
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 */
149 for (i=0; i<num_domains; i++) {
150 if (strequal(names[i], domain->name)) {
151 have_own_domain = True;
152 break;
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));
164 /* This is a bit excessive, but the extra data sooner or later will be
165 talloc'ed */
167 extra_data_len = 0;
168 if (extra_data != NULL) {
169 extra_data_len = strlen(extra_data);
172 if (extra_data_len > 0) {
173 state->response.extra_data.data = SMB_STRDUP(extra_data);
174 state->response.length += extra_data_len+1;
177 return WINBINDD_OK;
180 void winbindd_getdcname(struct winbindd_cli_state *state)
182 state->request.domain_name
183 [sizeof(state->request.domain_name)-1] = '\0';
185 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
186 state->request.domain_name));
188 sendto_domain(state, find_our_domain());
191 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
192 struct winbindd_cli_state *state)
194 fstring dcname_slash;
195 char *p;
196 struct rpc_pipe_client *netlogon_pipe;
197 NTSTATUS result;
198 WERROR werr;
200 state->request.domain_name
201 [sizeof(state->request.domain_name)-1] = '\0';
203 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
204 state->request.domain_name));
206 result = cm_connect_netlogon(domain, &netlogon_pipe);
208 if (!NT_STATUS_IS_OK(result)) {
209 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
210 return WINBINDD_ERROR;
213 werr = rpccli_netlogon_getdcname(netlogon_pipe, state->mem_ctx, domain->dcname,
214 state->request.domain_name,
215 dcname_slash);
217 if (!W_ERROR_IS_OK(werr)) {
218 DEBUG(5, ("Error requesting DCname: %s\n", dos_errstr(werr)));
219 return WINBINDD_ERROR;
222 p = dcname_slash;
223 if (*p == '\\') {
224 p+=1;
226 if (*p == '\\') {
227 p+=1;
230 fstrcpy(state->response.data.dc_name, p);
231 return WINBINDD_OK;
234 struct sequence_state {
235 TALLOC_CTX *mem_ctx;
236 struct winbindd_cli_state *cli_state;
237 struct winbindd_domain *domain;
238 struct winbindd_request *request;
239 struct winbindd_response *response;
240 char *extra_data;
243 static void sequence_recv(void *private_data, BOOL success);
245 void winbindd_show_sequence(struct winbindd_cli_state *state)
247 struct sequence_state *seq;
249 /* Ensure null termination */
250 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
252 if (strlen(state->request.domain_name) > 0) {
253 struct winbindd_domain *domain;
254 domain = find_domain_from_name_noinit(
255 state->request.domain_name);
256 if (domain == NULL) {
257 request_error(state);
258 return;
260 sendto_domain(state, domain);
261 return;
264 /* Ask all domains in sequence, collect the results in sequence_recv */
266 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
267 if (seq == NULL) {
268 DEBUG(0, ("talloc failed\n"));
269 request_error(state);
270 return;
273 seq->mem_ctx = state->mem_ctx;
274 seq->cli_state = state;
275 seq->domain = domain_list();
276 if (seq->domain == NULL) {
277 DEBUG(0, ("domain list empty\n"));
278 request_error(state);
279 return;
281 seq->request = TALLOC_ZERO_P(state->mem_ctx,
282 struct winbindd_request);
283 seq->response = TALLOC_ZERO_P(state->mem_ctx,
284 struct winbindd_response);
285 seq->extra_data = talloc_strdup(state->mem_ctx, "");
287 if ((seq->request == NULL) || (seq->response == NULL) ||
288 (seq->extra_data == NULL)) {
289 DEBUG(0, ("talloc failed\n"));
290 request_error(state);
291 return;
294 seq->request->length = sizeof(*seq->request);
295 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
296 fstrcpy(seq->request->domain_name, seq->domain->name);
298 async_domain_request(state->mem_ctx, seq->domain,
299 seq->request, seq->response,
300 sequence_recv, seq);
303 static void sequence_recv(void *private_data, BOOL success)
305 struct sequence_state *state =
306 (struct sequence_state *)private_data;
307 uint32 seq = DOM_SEQUENCE_NONE;
309 if ((success) && (state->response->result == WINBINDD_OK))
310 seq = state->response->data.domain_info.sequence_number;
312 if (seq == DOM_SEQUENCE_NONE) {
313 state->extra_data = talloc_asprintf(state->mem_ctx,
314 "%s%s : DISCONNECTED\n",
315 state->extra_data,
316 state->domain->name);
317 } else {
318 state->extra_data = talloc_asprintf(state->mem_ctx,
319 "%s%s : %d\n",
320 state->extra_data,
321 state->domain->name, seq);
324 state->domain->sequence_number = seq;
326 state->domain = state->domain->next;
328 if (state->domain == NULL) {
329 struct winbindd_cli_state *cli_state = state->cli_state;
330 cli_state->response.length =
331 sizeof(cli_state->response) +
332 strlen(state->extra_data) + 1;
333 cli_state->response.extra_data.data =
334 SMB_STRDUP(state->extra_data);
335 request_ok(cli_state);
336 return;
339 /* Ask the next domain */
340 fstrcpy(state->request->domain_name, state->domain->name);
341 async_domain_request(state->mem_ctx, state->domain,
342 state->request, state->response,
343 sequence_recv, state);
346 /* This is the child-only version of --sequence. It only allows for a single
347 * domain (ie "our" one) to be displayed. */
349 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
350 struct winbindd_cli_state *state)
352 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
354 /* Ensure null termination */
355 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
357 domain->methods->sequence_number(domain, &domain->sequence_number);
359 state->response.data.domain_info.sequence_number =
360 domain->sequence_number;
362 return WINBINDD_OK;
365 struct domain_info_state {
366 struct winbindd_domain *domain;
367 struct winbindd_cli_state *cli_state;
370 static void domain_info_init_recv(void *private_data, BOOL success);
372 void winbindd_domain_info(struct winbindd_cli_state *state)
374 struct winbindd_domain *domain;
376 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
377 state->request.domain_name));
379 domain = find_domain_from_name_noinit(state->request.domain_name);
381 if (domain == NULL) {
382 DEBUG(3, ("Did not find domain [%s]\n",
383 state->request.domain_name));
384 request_error(state);
385 return;
388 if (!domain->initialized) {
389 struct domain_info_state *istate;
391 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
392 if (istate == NULL) {
393 DEBUG(0, ("talloc failed\n"));
394 request_error(state);
395 return;
398 istate->cli_state = state;
399 istate->domain = domain;
401 init_child_connection(domain, domain_info_init_recv, istate);
403 return;
406 fstrcpy(state->response.data.domain_info.name,
407 domain->name);
408 fstrcpy(state->response.data.domain_info.alt_name,
409 domain->alt_name);
410 fstrcpy(state->response.data.domain_info.sid,
411 sid_string_static(&domain->sid));
413 state->response.data.domain_info.native_mode =
414 domain->native_mode;
415 state->response.data.domain_info.active_directory =
416 domain->active_directory;
417 state->response.data.domain_info.primary =
418 domain->primary;
419 state->response.data.domain_info.sequence_number =
420 domain->sequence_number;
422 request_ok(state);
425 static void domain_info_init_recv(void *private_data, BOOL success)
427 struct domain_info_state *istate =
428 (struct domain_info_state *)private_data;
429 struct winbindd_cli_state *state = istate->cli_state;
430 struct winbindd_domain *domain = istate->domain;
432 DEBUG(10, ("Got back from child init: %d\n", success));
434 if ((!success) || (!domain->initialized)) {
435 DEBUG(5, ("Could not init child for domain %s\n",
436 domain->name));
437 request_error(state);
438 return;
441 fstrcpy(state->response.data.domain_info.name,
442 domain->name);
443 fstrcpy(state->response.data.domain_info.alt_name,
444 domain->alt_name);
445 fstrcpy(state->response.data.domain_info.sid,
446 sid_string_static(&domain->sid));
448 state->response.data.domain_info.native_mode =
449 domain->native_mode;
450 state->response.data.domain_info.active_directory =
451 domain->active_directory;
452 state->response.data.domain_info.primary =
453 domain->primary;
454 state->response.data.domain_info.sequence_number =
455 domain->sequence_number;
457 request_ok(state);
460 void winbindd_ping(struct winbindd_cli_state *state)
462 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
463 request_ok(state);
466 /* List various tidbits of information */
468 void winbindd_info(struct winbindd_cli_state *state)
471 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
473 state->response.data.info.winbind_separator = *lp_winbind_separator();
474 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
475 request_ok(state);
478 /* Tell the client the current interface version */
480 void winbindd_interface_version(struct winbindd_cli_state *state)
482 DEBUG(3, ("[%5lu]: request interface version\n",
483 (unsigned long)state->pid));
485 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
486 request_ok(state);
489 /* What domain are we a member of? */
491 void winbindd_domain_name(struct winbindd_cli_state *state)
493 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
495 fstrcpy(state->response.data.domain_name, lp_workgroup());
496 request_ok(state);
499 /* What's my name again? */
501 void winbindd_netbios_name(struct winbindd_cli_state *state)
503 DEBUG(3, ("[%5lu]: request netbios name\n",
504 (unsigned long)state->pid));
506 fstrcpy(state->response.data.netbios_name, global_myname());
507 request_ok(state);
510 /* Where can I find the privilaged pipe? */
512 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
515 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
516 (unsigned long)state->pid));
518 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
519 if (!state->response.extra_data.data) {
520 DEBUG(0, ("malloc failed\n"));
521 request_error(state);
522 return;
525 /* must add one to length to copy the 0 for string termination */
526 state->response.length +=
527 strlen((char *)state->response.extra_data.data) + 1;
529 request_ok(state);