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 3 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, see <http://www.gnu.org/licenses/>.
27 #define DBGC_CLASS DBGC_WINBIND
29 /* Check the machine account password is valid */
31 void winbindd_check_machine_acct(struct winbindd_cli_state *state)
33 DEBUG(3, ("[%5lu]: check machine account\n",
34 (unsigned long)state->pid));
36 sendto_domain(state, find_our_domain());
39 enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
40 struct winbindd_cli_state *state)
42 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
44 struct winbindd_domain *contact_domain;
46 DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
48 /* Get trust account password */
52 contact_domain = find_our_domain();
54 /* This call does a cli_nt_setup_creds() which implicitly checks
55 the trust account password. */
57 invalidate_cm_connection(&contact_domain->conn);
60 struct rpc_pipe_client *netlogon_pipe;
61 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
64 if (!NT_STATUS_IS_OK(result)) {
65 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
69 /* There is a race condition between fetching the trust account
70 password and the periodic machine password change. So it's
71 possible that the trust account password has been changed on us.
72 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
76 if ((num_retries < MAX_RETRIES) &&
77 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
82 /* Pass back result code - zero for success, other values for
85 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
89 state->response.data.auth.nt_status = NT_STATUS_V(result);
90 fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
91 fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
92 state->response.data.auth.pam_error = nt_status_to_pam(result);
94 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
95 state->response.data.auth.nt_status_string));
97 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
100 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
102 struct winbindd_domain *d = NULL;
103 int extra_data_len = 0;
104 char *extra_data = NULL;
106 DEBUG(3, ("[%5lu]: list trusted domains\n",
107 (unsigned long)state->pid));
109 for ( d=domain_list(); d; d=d->next ) {
111 extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
113 d->alt_name ? d->alt_name : d->name,
114 sid_string_static(&d->sid));
116 extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
119 d->alt_name ? d->alt_name : d->name,
120 sid_string_static(&d->sid));
125 if (extra_data != NULL) {
126 extra_data_len = strlen(extra_data);
129 if (extra_data_len > 0) {
130 state->response.extra_data.data = SMB_STRDUP(extra_data);
131 state->response.length += extra_data_len+1;
134 TALLOC_FREE( extra_data );
139 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
140 struct winbindd_cli_state *state)
142 uint32 i, num_domains;
143 char **names, **alt_names;
145 int extra_data_len = 0;
148 BOOL have_own_domain = False;
150 DEBUG(3, ("[%5lu]: list trusted domains\n",
151 (unsigned long)state->pid));
153 result = domain->methods->trusted_domains(domain, state->mem_ctx,
154 &num_domains, &names,
157 if (!NT_STATUS_IS_OK(result)) {
158 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
159 nt_errstr(result) ));
160 return WINBINDD_ERROR;
163 extra_data = talloc_strdup(state->mem_ctx, "");
166 extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
168 alt_names[0] ? alt_names[0] : names[0],
169 sid_string_static(&sids[0]));
171 for (i=1; i<num_domains; i++)
172 extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
175 alt_names[i] ? alt_names[i] : names[i],
176 sid_string_static(&sids[i]));
177 /* add our primary domain */
179 for (i=0; i<num_domains; i++) {
180 if (strequal(names[i], domain->name)) {
181 have_own_domain = True;
186 if (state->request.data.list_all_domains && !have_own_domain) {
187 extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
190 domain->alt_name ? domain->alt_name : domain->name,
191 sid_string_static(&domain->sid));
194 /* This is a bit excessive, but the extra data sooner or later will be
198 if (extra_data != NULL) {
199 extra_data_len = strlen(extra_data);
202 if (extra_data_len > 0) {
203 state->response.extra_data.data = SMB_STRDUP(extra_data);
204 state->response.length += extra_data_len+1;
210 void winbindd_getdcname(struct winbindd_cli_state *state)
212 struct winbindd_domain *domain;
214 state->request.domain_name
215 [sizeof(state->request.domain_name)-1] = '\0';
217 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
218 state->request.domain_name));
220 domain = find_domain_from_name_noinit(state->request.domain_name);
221 if (domain && domain->internal) {
222 fstrcpy(state->response.data.dc_name, global_myname());
227 sendto_domain(state, find_our_domain());
230 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
231 struct winbindd_cli_state *state)
233 fstring dcname_slash;
235 struct rpc_pipe_client *netlogon_pipe;
238 unsigned int orig_timeout;
239 struct winbindd_domain *req_domain;
241 state->request.domain_name
242 [sizeof(state->request.domain_name)-1] = '\0';
244 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
245 state->request.domain_name));
247 result = cm_connect_netlogon(domain, &netlogon_pipe);
249 if (!NT_STATUS_IS_OK(result)) {
250 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
251 return WINBINDD_ERROR;
254 /* This call can take a long time - allow the server to time out.
255 35 seconds should do it. */
257 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
259 req_domain = find_domain_from_name_noinit(state->request.domain_name);
260 if (req_domain == domain) {
261 werr = rpccli_netlogon_getdcname(netlogon_pipe, state->mem_ctx,
263 state->request.domain_name,
266 werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx,
268 state->request.domain_name,
271 /* And restore our original timeout. */
272 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
274 if (!W_ERROR_IS_OK(werr)) {
275 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
276 state->request.domain_name, dos_errstr(werr)));
277 return WINBINDD_ERROR;
288 fstrcpy(state->response.data.dc_name, p);
292 static struct winbindd_child static_locator_child;
294 void init_locator_child(void)
296 setup_domain_child(NULL, &static_locator_child, "locator");
299 struct winbindd_child *locator_child(void)
301 return &static_locator_child;
304 void winbindd_dsgetdcname(struct winbindd_cli_state *state)
306 state->request.domain_name
307 [sizeof(state->request.domain_name)-1] = '\0';
309 DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid,
310 state->request.domain_name));
312 sendto_child(state, locator_child());
315 enum winbindd_result winbindd_dual_dsgetdcname(struct winbindd_domain *domain,
316 struct winbindd_cli_state *state)
319 struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
320 const char *dc = NULL;
322 state->request.domain_name
323 [sizeof(state->request.domain_name)-1] = '\0';
325 DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid,
326 state->request.domain_name));
328 result = DsGetDcName(state->mem_ctx, NULL, state->request.domain_name,
329 NULL, NULL, state->request.flags, &info);
331 if (!NT_STATUS_IS_OK(result)) {
332 return WINBINDD_ERROR;
335 if (info->domain_controller_address) {
336 dc = info->domain_controller_address;
337 if ((dc[0] == '\\') && (dc[1] == '\\')) {
342 if ((!dc || !is_ipaddress(dc)) && info->domain_controller_name) {
343 dc = info->domain_controller_name;
347 return WINBINDD_ERROR;
350 fstrcpy(state->response.data.dc_name, dc);
356 struct sequence_state {
358 struct winbindd_cli_state *cli_state;
359 struct winbindd_domain *domain;
360 struct winbindd_request *request;
361 struct winbindd_response *response;
365 static void sequence_recv(void *private_data, BOOL success);
367 void winbindd_show_sequence(struct winbindd_cli_state *state)
369 struct sequence_state *seq;
371 /* Ensure null termination */
372 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
374 if (strlen(state->request.domain_name) > 0) {
375 struct winbindd_domain *domain;
376 domain = find_domain_from_name_noinit(
377 state->request.domain_name);
378 if (domain == NULL) {
379 request_error(state);
382 sendto_domain(state, domain);
386 /* Ask all domains in sequence, collect the results in sequence_recv */
388 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
390 DEBUG(0, ("talloc failed\n"));
391 request_error(state);
395 seq->mem_ctx = state->mem_ctx;
396 seq->cli_state = state;
397 seq->domain = domain_list();
398 if (seq->domain == NULL) {
399 DEBUG(0, ("domain list empty\n"));
400 request_error(state);
403 seq->request = TALLOC_ZERO_P(state->mem_ctx,
404 struct winbindd_request);
405 seq->response = TALLOC_ZERO_P(state->mem_ctx,
406 struct winbindd_response);
407 seq->extra_data = talloc_strdup(state->mem_ctx, "");
409 if ((seq->request == NULL) || (seq->response == NULL) ||
410 (seq->extra_data == NULL)) {
411 DEBUG(0, ("talloc failed\n"));
412 request_error(state);
416 seq->request->length = sizeof(*seq->request);
417 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
418 fstrcpy(seq->request->domain_name, seq->domain->name);
420 async_domain_request(state->mem_ctx, seq->domain,
421 seq->request, seq->response,
425 static void sequence_recv(void *private_data, BOOL success)
427 struct sequence_state *state =
428 (struct sequence_state *)private_data;
429 uint32 seq = DOM_SEQUENCE_NONE;
431 if ((success) && (state->response->result == WINBINDD_OK))
432 seq = state->response->data.sequence_number;
434 if (seq == DOM_SEQUENCE_NONE) {
435 state->extra_data = talloc_asprintf(state->mem_ctx,
436 "%s%s : DISCONNECTED\n",
438 state->domain->name);
440 state->extra_data = talloc_asprintf(state->mem_ctx,
443 state->domain->name, seq);
446 state->domain->sequence_number = seq;
448 state->domain = state->domain->next;
450 if (state->domain == NULL) {
451 struct winbindd_cli_state *cli_state = state->cli_state;
452 cli_state->response.length =
453 sizeof(cli_state->response) +
454 strlen(state->extra_data) + 1;
455 cli_state->response.extra_data.data =
456 SMB_STRDUP(state->extra_data);
457 request_ok(cli_state);
461 /* Ask the next domain */
462 fstrcpy(state->request->domain_name, state->domain->name);
463 async_domain_request(state->mem_ctx, state->domain,
464 state->request, state->response,
465 sequence_recv, state);
468 /* This is the child-only version of --sequence. It only allows for a single
469 * domain (ie "our" one) to be displayed. */
471 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
472 struct winbindd_cli_state *state)
474 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
476 /* Ensure null termination */
477 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
479 domain->methods->sequence_number(domain, &domain->sequence_number);
481 state->response.data.sequence_number =
482 domain->sequence_number;
487 struct domain_info_state {
488 struct winbindd_domain *domain;
489 struct winbindd_cli_state *cli_state;
492 static void domain_info_init_recv(void *private_data, BOOL success);
494 void winbindd_domain_info(struct winbindd_cli_state *state)
496 struct winbindd_domain *domain;
498 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
499 state->request.domain_name));
501 domain = find_domain_from_name_noinit(state->request.domain_name);
503 if (domain == NULL) {
504 DEBUG(3, ("Did not find domain [%s]\n",
505 state->request.domain_name));
506 request_error(state);
510 if (!domain->initialized) {
511 struct domain_info_state *istate;
513 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
514 if (istate == NULL) {
515 DEBUG(0, ("talloc failed\n"));
516 request_error(state);
520 istate->cli_state = state;
521 istate->domain = domain;
523 init_child_connection(domain, domain_info_init_recv, istate);
528 fstrcpy(state->response.data.domain_info.name,
530 fstrcpy(state->response.data.domain_info.alt_name,
532 fstrcpy(state->response.data.domain_info.sid,
533 sid_string_static(&domain->sid));
535 state->response.data.domain_info.native_mode =
537 state->response.data.domain_info.active_directory =
538 domain->active_directory;
539 state->response.data.domain_info.primary =
545 static void domain_info_init_recv(void *private_data, BOOL success)
547 struct domain_info_state *istate =
548 (struct domain_info_state *)private_data;
549 struct winbindd_cli_state *state = istate->cli_state;
550 struct winbindd_domain *domain = istate->domain;
552 DEBUG(10, ("Got back from child init: %d\n", success));
554 if ((!success) || (!domain->initialized)) {
555 DEBUG(5, ("Could not init child for domain %s\n",
557 request_error(state);
561 fstrcpy(state->response.data.domain_info.name,
563 fstrcpy(state->response.data.domain_info.alt_name,
565 fstrcpy(state->response.data.domain_info.sid,
566 sid_string_static(&domain->sid));
568 state->response.data.domain_info.native_mode =
570 state->response.data.domain_info.active_directory =
571 domain->active_directory;
572 state->response.data.domain_info.primary =
578 void winbindd_ping(struct winbindd_cli_state *state)
580 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
584 /* List various tidbits of information */
586 void winbindd_info(struct winbindd_cli_state *state)
589 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
591 state->response.data.info.winbind_separator = *lp_winbind_separator();
592 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
596 /* Tell the client the current interface version */
598 void winbindd_interface_version(struct winbindd_cli_state *state)
600 DEBUG(3, ("[%5lu]: request interface version\n",
601 (unsigned long)state->pid));
603 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
607 /* What domain are we a member of? */
609 void winbindd_domain_name(struct winbindd_cli_state *state)
611 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
613 fstrcpy(state->response.data.domain_name, lp_workgroup());
617 /* What's my name again? */
619 void winbindd_netbios_name(struct winbindd_cli_state *state)
621 DEBUG(3, ("[%5lu]: request netbios name\n",
622 (unsigned long)state->pid));
624 fstrcpy(state->response.data.netbios_name, global_myname());
628 /* Where can I find the privilaged pipe? */
630 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
633 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
634 (unsigned long)state->pid));
636 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
637 if (!state->response.extra_data.data) {
638 DEBUG(0, ("malloc failed\n"));
639 request_error(state);
643 /* must add one to length to copy the 0 for string termination */
644 state->response.length +=
645 strlen((char *)state->response.extra_data.data) + 1;