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 state->request.domain_name
213 [sizeof(state->request.domain_name)-1] = '\0';
215 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
216 state->request.domain_name));
218 sendto_domain(state, find_our_domain());
221 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
222 struct winbindd_cli_state *state)
224 fstring dcname_slash;
226 struct rpc_pipe_client *netlogon_pipe;
229 unsigned int orig_timeout;
231 state->request.domain_name
232 [sizeof(state->request.domain_name)-1] = '\0';
234 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
235 state->request.domain_name));
237 result = cm_connect_netlogon(domain, &netlogon_pipe);
239 if (!NT_STATUS_IS_OK(result)) {
240 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
241 return WINBINDD_ERROR;
244 /* This call can take a long time - allow the server to time out.
245 35 seconds should do it. */
247 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
249 werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx, domain->dcname,
250 state->request.domain_name,
252 /* And restore our original timeout. */
253 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
255 if (!W_ERROR_IS_OK(werr)) {
256 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
257 state->request.domain_name, dos_errstr(werr)));
258 return WINBINDD_ERROR;
269 fstrcpy(state->response.data.dc_name, p);
273 static struct winbindd_child static_locator_child;
275 void init_locator_child(void)
277 setup_domain_child(NULL, &static_locator_child, "locator");
280 struct winbindd_child *locator_child(void)
282 return &static_locator_child;
285 void winbindd_dsgetdcname(struct winbindd_cli_state *state)
287 state->request.domain_name
288 [sizeof(state->request.domain_name)-1] = '\0';
290 DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid,
291 state->request.domain_name));
293 sendto_child(state, locator_child());
296 enum winbindd_result winbindd_dual_dsgetdcname(struct winbindd_domain *domain,
297 struct winbindd_cli_state *state)
300 struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
301 const char *dc = NULL;
303 state->request.domain_name
304 [sizeof(state->request.domain_name)-1] = '\0';
306 DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid,
307 state->request.domain_name));
309 result = DsGetDcName(state->mem_ctx, NULL, state->request.domain_name,
310 NULL, NULL, state->request.flags, &info);
312 if (!NT_STATUS_IS_OK(result)) {
313 return WINBINDD_ERROR;
316 if (info->domain_controller_address) {
317 dc = info->domain_controller_address;
318 if ((dc[0] == '\\') && (dc[1] == '\\')) {
323 if ((!dc || !is_ipaddress(dc)) && info->domain_controller_name) {
324 dc = info->domain_controller_name;
328 return WINBINDD_ERROR;
331 fstrcpy(state->response.data.dc_name, dc);
337 struct sequence_state {
339 struct winbindd_cli_state *cli_state;
340 struct winbindd_domain *domain;
341 struct winbindd_request *request;
342 struct winbindd_response *response;
346 static void sequence_recv(void *private_data, BOOL success);
348 void winbindd_show_sequence(struct winbindd_cli_state *state)
350 struct sequence_state *seq;
352 /* Ensure null termination */
353 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
355 if (strlen(state->request.domain_name) > 0) {
356 struct winbindd_domain *domain;
357 domain = find_domain_from_name_noinit(
358 state->request.domain_name);
359 if (domain == NULL) {
360 request_error(state);
363 sendto_domain(state, domain);
367 /* Ask all domains in sequence, collect the results in sequence_recv */
369 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
371 DEBUG(0, ("talloc failed\n"));
372 request_error(state);
376 seq->mem_ctx = state->mem_ctx;
377 seq->cli_state = state;
378 seq->domain = domain_list();
379 if (seq->domain == NULL) {
380 DEBUG(0, ("domain list empty\n"));
381 request_error(state);
384 seq->request = TALLOC_ZERO_P(state->mem_ctx,
385 struct winbindd_request);
386 seq->response = TALLOC_ZERO_P(state->mem_ctx,
387 struct winbindd_response);
388 seq->extra_data = talloc_strdup(state->mem_ctx, "");
390 if ((seq->request == NULL) || (seq->response == NULL) ||
391 (seq->extra_data == NULL)) {
392 DEBUG(0, ("talloc failed\n"));
393 request_error(state);
397 seq->request->length = sizeof(*seq->request);
398 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
399 fstrcpy(seq->request->domain_name, seq->domain->name);
401 async_domain_request(state->mem_ctx, seq->domain,
402 seq->request, seq->response,
406 static void sequence_recv(void *private_data, BOOL success)
408 struct sequence_state *state =
409 (struct sequence_state *)private_data;
410 uint32 seq = DOM_SEQUENCE_NONE;
412 if ((success) && (state->response->result == WINBINDD_OK))
413 seq = state->response->data.sequence_number;
415 if (seq == DOM_SEQUENCE_NONE) {
416 state->extra_data = talloc_asprintf(state->mem_ctx,
417 "%s%s : DISCONNECTED\n",
419 state->domain->name);
421 state->extra_data = talloc_asprintf(state->mem_ctx,
424 state->domain->name, seq);
427 state->domain->sequence_number = seq;
429 state->domain = state->domain->next;
431 if (state->domain == NULL) {
432 struct winbindd_cli_state *cli_state = state->cli_state;
433 cli_state->response.length =
434 sizeof(cli_state->response) +
435 strlen(state->extra_data) + 1;
436 cli_state->response.extra_data.data =
437 SMB_STRDUP(state->extra_data);
438 request_ok(cli_state);
442 /* Ask the next domain */
443 fstrcpy(state->request->domain_name, state->domain->name);
444 async_domain_request(state->mem_ctx, state->domain,
445 state->request, state->response,
446 sequence_recv, state);
449 /* This is the child-only version of --sequence. It only allows for a single
450 * domain (ie "our" one) to be displayed. */
452 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
453 struct winbindd_cli_state *state)
455 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
457 /* Ensure null termination */
458 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
460 domain->methods->sequence_number(domain, &domain->sequence_number);
462 state->response.data.sequence_number =
463 domain->sequence_number;
468 struct domain_info_state {
469 struct winbindd_domain *domain;
470 struct winbindd_cli_state *cli_state;
473 static void domain_info_init_recv(void *private_data, BOOL success);
475 void winbindd_domain_info(struct winbindd_cli_state *state)
477 struct winbindd_domain *domain;
479 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
480 state->request.domain_name));
482 domain = find_domain_from_name_noinit(state->request.domain_name);
484 if (domain == NULL) {
485 DEBUG(3, ("Did not find domain [%s]\n",
486 state->request.domain_name));
487 request_error(state);
491 if (!domain->initialized) {
492 struct domain_info_state *istate;
494 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
495 if (istate == NULL) {
496 DEBUG(0, ("talloc failed\n"));
497 request_error(state);
501 istate->cli_state = state;
502 istate->domain = domain;
504 init_child_connection(domain, domain_info_init_recv, istate);
509 fstrcpy(state->response.data.domain_info.name,
511 fstrcpy(state->response.data.domain_info.alt_name,
513 fstrcpy(state->response.data.domain_info.sid,
514 sid_string_static(&domain->sid));
516 state->response.data.domain_info.native_mode =
518 state->response.data.domain_info.active_directory =
519 domain->active_directory;
520 state->response.data.domain_info.primary =
526 static void domain_info_init_recv(void *private_data, BOOL success)
528 struct domain_info_state *istate =
529 (struct domain_info_state *)private_data;
530 struct winbindd_cli_state *state = istate->cli_state;
531 struct winbindd_domain *domain = istate->domain;
533 DEBUG(10, ("Got back from child init: %d\n", success));
535 if ((!success) || (!domain->initialized)) {
536 DEBUG(5, ("Could not init child for domain %s\n",
538 request_error(state);
542 fstrcpy(state->response.data.domain_info.name,
544 fstrcpy(state->response.data.domain_info.alt_name,
546 fstrcpy(state->response.data.domain_info.sid,
547 sid_string_static(&domain->sid));
549 state->response.data.domain_info.native_mode =
551 state->response.data.domain_info.active_directory =
552 domain->active_directory;
553 state->response.data.domain_info.primary =
559 void winbindd_ping(struct winbindd_cli_state *state)
561 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
565 /* List various tidbits of information */
567 void winbindd_info(struct winbindd_cli_state *state)
570 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
572 state->response.data.info.winbind_separator = *lp_winbind_separator();
573 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
577 /* Tell the client the current interface version */
579 void winbindd_interface_version(struct winbindd_cli_state *state)
581 DEBUG(3, ("[%5lu]: request interface version\n",
582 (unsigned long)state->pid));
584 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
588 /* What domain are we a member of? */
590 void winbindd_domain_name(struct winbindd_cli_state *state)
592 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
594 fstrcpy(state->response.data.domain_name, lp_workgroup());
598 /* What's my name again? */
600 void winbindd_netbios_name(struct winbindd_cli_state *state)
602 DEBUG(3, ("[%5lu]: request netbios name\n",
603 (unsigned long)state->pid));
605 fstrcpy(state->response.data.netbios_name, global_myname());
609 /* Where can I find the privilaged pipe? */
611 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
614 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
615 (unsigned long)state->pid));
617 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
618 if (!state->response.extra_data.data) {
619 DEBUG(0, ("malloc failed\n"));
620 request_error(state);
624 /* must add one to length to copy the 0 for string termination */
625 state->response.length +=
626 strlen((char *)state->response.extra_data.data) + 1;