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;
240 state->request.domain_name
241 [sizeof(state->request.domain_name)-1] = '\0';
243 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
244 state->request.domain_name));
246 result = cm_connect_netlogon(domain, &netlogon_pipe);
248 if (!NT_STATUS_IS_OK(result)) {
249 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
250 return WINBINDD_ERROR;
253 /* This call can take a long time - allow the server to time out.
254 35 seconds should do it. */
256 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
258 werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx, domain->dcname,
259 state->request.domain_name,
261 /* And restore our original timeout. */
262 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
264 if (!W_ERROR_IS_OK(werr)) {
265 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
266 state->request.domain_name, dos_errstr(werr)));
267 return WINBINDD_ERROR;
278 fstrcpy(state->response.data.dc_name, p);
282 static struct winbindd_child static_locator_child;
284 void init_locator_child(void)
286 setup_domain_child(NULL, &static_locator_child, "locator");
289 struct winbindd_child *locator_child(void)
291 return &static_locator_child;
294 void winbindd_dsgetdcname(struct winbindd_cli_state *state)
296 state->request.domain_name
297 [sizeof(state->request.domain_name)-1] = '\0';
299 DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid,
300 state->request.domain_name));
302 sendto_child(state, locator_child());
305 enum winbindd_result winbindd_dual_dsgetdcname(struct winbindd_domain *domain,
306 struct winbindd_cli_state *state)
309 struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
310 const char *dc = NULL;
312 state->request.domain_name
313 [sizeof(state->request.domain_name)-1] = '\0';
315 DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid,
316 state->request.domain_name));
318 result = DsGetDcName(state->mem_ctx, NULL, state->request.domain_name,
319 NULL, NULL, state->request.flags, &info);
321 if (!NT_STATUS_IS_OK(result)) {
322 return WINBINDD_ERROR;
325 if (info->domain_controller_address) {
326 dc = info->domain_controller_address;
327 if ((dc[0] == '\\') && (dc[1] == '\\')) {
332 if ((!dc || !is_ipaddress(dc)) && info->domain_controller_name) {
333 dc = info->domain_controller_name;
337 return WINBINDD_ERROR;
340 fstrcpy(state->response.data.dc_name, dc);
346 struct sequence_state {
348 struct winbindd_cli_state *cli_state;
349 struct winbindd_domain *domain;
350 struct winbindd_request *request;
351 struct winbindd_response *response;
355 static void sequence_recv(void *private_data, BOOL success);
357 void winbindd_show_sequence(struct winbindd_cli_state *state)
359 struct sequence_state *seq;
361 /* Ensure null termination */
362 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
364 if (strlen(state->request.domain_name) > 0) {
365 struct winbindd_domain *domain;
366 domain = find_domain_from_name_noinit(
367 state->request.domain_name);
368 if (domain == NULL) {
369 request_error(state);
372 sendto_domain(state, domain);
376 /* Ask all domains in sequence, collect the results in sequence_recv */
378 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
380 DEBUG(0, ("talloc failed\n"));
381 request_error(state);
385 seq->mem_ctx = state->mem_ctx;
386 seq->cli_state = state;
387 seq->domain = domain_list();
388 if (seq->domain == NULL) {
389 DEBUG(0, ("domain list empty\n"));
390 request_error(state);
393 seq->request = TALLOC_ZERO_P(state->mem_ctx,
394 struct winbindd_request);
395 seq->response = TALLOC_ZERO_P(state->mem_ctx,
396 struct winbindd_response);
397 seq->extra_data = talloc_strdup(state->mem_ctx, "");
399 if ((seq->request == NULL) || (seq->response == NULL) ||
400 (seq->extra_data == NULL)) {
401 DEBUG(0, ("talloc failed\n"));
402 request_error(state);
406 seq->request->length = sizeof(*seq->request);
407 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
408 fstrcpy(seq->request->domain_name, seq->domain->name);
410 async_domain_request(state->mem_ctx, seq->domain,
411 seq->request, seq->response,
415 static void sequence_recv(void *private_data, BOOL success)
417 struct sequence_state *state =
418 (struct sequence_state *)private_data;
419 uint32 seq = DOM_SEQUENCE_NONE;
421 if ((success) && (state->response->result == WINBINDD_OK))
422 seq = state->response->data.sequence_number;
424 if (seq == DOM_SEQUENCE_NONE) {
425 state->extra_data = talloc_asprintf(state->mem_ctx,
426 "%s%s : DISCONNECTED\n",
428 state->domain->name);
430 state->extra_data = talloc_asprintf(state->mem_ctx,
433 state->domain->name, seq);
436 state->domain->sequence_number = seq;
438 state->domain = state->domain->next;
440 if (state->domain == NULL) {
441 struct winbindd_cli_state *cli_state = state->cli_state;
442 cli_state->response.length =
443 sizeof(cli_state->response) +
444 strlen(state->extra_data) + 1;
445 cli_state->response.extra_data.data =
446 SMB_STRDUP(state->extra_data);
447 request_ok(cli_state);
451 /* Ask the next domain */
452 fstrcpy(state->request->domain_name, state->domain->name);
453 async_domain_request(state->mem_ctx, state->domain,
454 state->request, state->response,
455 sequence_recv, state);
458 /* This is the child-only version of --sequence. It only allows for a single
459 * domain (ie "our" one) to be displayed. */
461 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
462 struct winbindd_cli_state *state)
464 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
466 /* Ensure null termination */
467 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
469 domain->methods->sequence_number(domain, &domain->sequence_number);
471 state->response.data.sequence_number =
472 domain->sequence_number;
477 struct domain_info_state {
478 struct winbindd_domain *domain;
479 struct winbindd_cli_state *cli_state;
482 static void domain_info_init_recv(void *private_data, BOOL success);
484 void winbindd_domain_info(struct winbindd_cli_state *state)
486 struct winbindd_domain *domain;
488 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
489 state->request.domain_name));
491 domain = find_domain_from_name_noinit(state->request.domain_name);
493 if (domain == NULL) {
494 DEBUG(3, ("Did not find domain [%s]\n",
495 state->request.domain_name));
496 request_error(state);
500 if (!domain->initialized) {
501 struct domain_info_state *istate;
503 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
504 if (istate == NULL) {
505 DEBUG(0, ("talloc failed\n"));
506 request_error(state);
510 istate->cli_state = state;
511 istate->domain = domain;
513 init_child_connection(domain, domain_info_init_recv, istate);
518 fstrcpy(state->response.data.domain_info.name,
520 fstrcpy(state->response.data.domain_info.alt_name,
522 fstrcpy(state->response.data.domain_info.sid,
523 sid_string_static(&domain->sid));
525 state->response.data.domain_info.native_mode =
527 state->response.data.domain_info.active_directory =
528 domain->active_directory;
529 state->response.data.domain_info.primary =
535 static void domain_info_init_recv(void *private_data, BOOL success)
537 struct domain_info_state *istate =
538 (struct domain_info_state *)private_data;
539 struct winbindd_cli_state *state = istate->cli_state;
540 struct winbindd_domain *domain = istate->domain;
542 DEBUG(10, ("Got back from child init: %d\n", success));
544 if ((!success) || (!domain->initialized)) {
545 DEBUG(5, ("Could not init child for domain %s\n",
547 request_error(state);
551 fstrcpy(state->response.data.domain_info.name,
553 fstrcpy(state->response.data.domain_info.alt_name,
555 fstrcpy(state->response.data.domain_info.sid,
556 sid_string_static(&domain->sid));
558 state->response.data.domain_info.native_mode =
560 state->response.data.domain_info.active_directory =
561 domain->active_directory;
562 state->response.data.domain_info.primary =
568 void winbindd_ping(struct winbindd_cli_state *state)
570 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
574 /* List various tidbits of information */
576 void winbindd_info(struct winbindd_cli_state *state)
579 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
581 state->response.data.info.winbind_separator = *lp_winbind_separator();
582 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
586 /* Tell the client the current interface version */
588 void winbindd_interface_version(struct winbindd_cli_state *state)
590 DEBUG(3, ("[%5lu]: request interface version\n",
591 (unsigned long)state->pid));
593 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
597 /* What domain are we a member of? */
599 void winbindd_domain_name(struct winbindd_cli_state *state)
601 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
603 fstrcpy(state->response.data.domain_name, lp_workgroup());
607 /* What's my name again? */
609 void winbindd_netbios_name(struct winbindd_cli_state *state)
611 DEBUG(3, ("[%5lu]: request netbios name\n",
612 (unsigned long)state->pid));
614 fstrcpy(state->response.data.netbios_name, global_myname());
618 /* Where can I find the privilaged pipe? */
620 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
623 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
624 (unsigned long)state->pid));
626 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
627 if (!state->response.extra_data.data) {
628 DEBUG(0, ("malloc failed\n"));
629 request_error(state);
633 /* must add one to length to copy the 0 for string termination */
634 state->response.length +=
635 strlen((char *)state->response.extra_data.data) + 1;