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 /* Constants and helper functions for determining domain trust types */
109 const char *trust_type_strings[] = {"External",
114 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
116 if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)
118 else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
120 else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
121 ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
126 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
128 return trust_type_strings[get_trust_type(domain)];
131 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
133 return (domain->trust_flags == 0x0) ||
134 ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
135 NETR_TRUST_FLAG_IN_FOREST) ||
136 ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
137 NETR_TRUST_FLAG_INBOUND);
140 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
142 return (domain->trust_flags == 0x0) ||
143 ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
144 NETR_TRUST_FLAG_IN_FOREST) ||
145 ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
146 NETR_TRUST_FLAG_OUTBOUND);
149 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
151 if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||
152 (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
153 (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
158 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
160 struct winbindd_tdc_domain *dom_list = NULL;
161 struct winbindd_tdc_domain *d = NULL;
162 size_t num_domains = 0;
163 int extra_data_len = 0;
164 char *extra_data = NULL;
167 DEBUG(3, ("[%5lu]: list trusted domains\n",
168 (unsigned long)state->pid));
170 if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
171 request_error(state);
175 for ( i = 0; i < num_domains; i++ ) {
176 struct winbindd_domain *domain;
177 bool is_online = true;
180 domain = find_domain_from_name_noinit(d->domain_name);
182 is_online = domain->online;
186 extra_data = talloc_asprintf(state->mem_ctx,
187 "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
189 d->dns_name ? d->dns_name : d->domain_name,
190 sid_string_talloc(state->mem_ctx, &d->sid),
191 get_trust_type_string(d),
192 trust_is_transitive(d) ? "Yes" : "No",
193 trust_is_inbound(d) ? "Yes" : "No",
194 trust_is_outbound(d) ? "Yes" : "No",
195 is_online ? "Online" : "Offline" );
197 extra_data = talloc_asprintf(state->mem_ctx,
198 "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
201 d->dns_name ? d->dns_name : d->domain_name,
202 sid_string_talloc(state->mem_ctx, &d->sid),
203 get_trust_type_string(d),
204 trust_is_transitive(d) ? "Yes" : "No",
205 trust_is_inbound(d) ? "Yes" : "No",
206 trust_is_outbound(d) ? "Yes" : "No",
207 is_online ? "Online" : "Offline" );
212 if (extra_data != NULL) {
213 extra_data_len = strlen(extra_data);
216 if (extra_data_len > 0) {
217 state->response.extra_data.data = SMB_STRDUP(extra_data);
218 state->response.length += extra_data_len+1;
223 TALLOC_FREE( dom_list );
224 TALLOC_FREE( extra_data );
227 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
228 struct winbindd_cli_state *state)
230 uint32 i, num_domains;
231 char **names, **alt_names;
233 int extra_data_len = 0;
236 bool have_own_domain = False;
238 DEBUG(3, ("[%5lu]: list trusted domains\n",
239 (unsigned long)state->pid));
241 result = domain->methods->trusted_domains(domain, state->mem_ctx,
242 &num_domains, &names,
245 if (!NT_STATUS_IS_OK(result)) {
246 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
247 nt_errstr(result) ));
248 return WINBINDD_ERROR;
251 extra_data = talloc_strdup(state->mem_ctx, "");
254 extra_data = talloc_asprintf(
255 state->mem_ctx, "%s\\%s\\%s",
256 names[0], alt_names[0] ? alt_names[0] : names[0],
257 sid_string_talloc(state->mem_ctx, &sids[0]));
259 for (i=1; i<num_domains; i++)
260 extra_data = talloc_asprintf(
261 state->mem_ctx, "%s\n%s\\%s\\%s",
262 extra_data, names[i],
263 alt_names[i] ? alt_names[i] : names[i],
264 sid_string_talloc(state->mem_ctx, &sids[i]));
266 /* add our primary domain */
268 for (i=0; i<num_domains; i++) {
269 if (strequal(names[i], domain->name)) {
270 have_own_domain = True;
275 if (state->request.data.list_all_domains && !have_own_domain) {
276 extra_data = talloc_asprintf(
277 state->mem_ctx, "%s\n%s\\%s\\%s",
278 extra_data, domain->name,
279 domain->alt_name ? domain->alt_name : domain->name,
280 sid_string_talloc(state->mem_ctx, &domain->sid));
283 /* This is a bit excessive, but the extra data sooner or later will be
287 if (extra_data != NULL) {
288 extra_data_len = strlen(extra_data);
291 if (extra_data_len > 0) {
292 state->response.extra_data.data = SMB_STRDUP(extra_data);
293 state->response.length += extra_data_len+1;
299 static void winbindd_getdcname_recv(void *private_data,
301 struct winbind_get_dc_info *r)
303 struct winbindd_cli_state *state =
304 talloc_get_type_abort(private_data, struct winbindd_cli_state);
307 request_error(state);
311 fstrcpy(state->response.data.dc_name, r->out.dc_info->name);
316 void winbindd_getdcname(struct winbindd_cli_state *state)
318 struct winbindd_domain *domain;
319 struct winbind_get_dc_info *r;
321 state->request.domain_name
322 [sizeof(state->request.domain_name)-1] = '\0';
324 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
325 state->request.domain_name));
327 domain = find_domain_from_name_noinit(state->request.domain_name);
328 if (domain && domain->internal) {
329 fstrcpy(state->response.data.dc_name, global_myname());
334 r = TALLOC_P(state->mem_ctx, struct winbind_get_dc_info);
336 r->in.level = TALLOC_P(r, enum winbind_dc_info_level);
337 if (!r->in.level) goto nomem;
339 *r->in.level = WINBIND_DC_INFO_LEVEL_COMPAT_NT4;
340 r->in.domain_name = state->request.domain_name;
342 winbindd_get_dc_info_async_domain(state->mem_ctx, find_our_domain(),
343 r, winbindd_getdcname_recv, state);
346 request_error(state);
350 static void winbindd_get_dc_info_recv(TALLOC_CTX *mem_ctx, bool success,
351 struct winbindd_ndr_call *c,
356 void (*cont)(void *priv, bool succ, struct winbind_get_dc_info *r) =
357 (void (*)(void *, bool, struct winbind_get_dc_info*))_cont;
358 struct winbind_get_dc_info *r =
359 talloc_get_type_abort(_r, struct winbind_get_dc_info);
362 DEBUG(5, ("Could not get dc_info\n"));
363 cont(private_data, False, r);
367 if (r->out.result != WINBIND_STATUS_OK) {
368 DEBUG(5, ("get_dc_info returned an error:0x%08X\n",
370 cont(private_data, False, r);
374 cont(private_data, True, r);
377 void winbindd_get_dc_info_async_domain(TALLOC_CTX *mem_ctx,
378 struct winbindd_domain *domain,
379 struct winbind_get_dc_info *r,
380 void (*cont)(void *private_data,
382 struct winbind_get_dc_info *r),
385 do_async_ndr_domain(mem_ctx, domain,
386 NDR_WINBIND_GET_DC_INFO, r,
387 winbindd_get_dc_info_recv, r,
388 (void *)cont, private_data);
391 void winbindd_get_dc_info_async_child(TALLOC_CTX *mem_ctx,
392 struct winbindd_child *child,
393 struct winbind_get_dc_info *r,
394 void (*cont)(void *private_data,
396 struct winbind_get_dc_info *r),
399 do_async_ndr(mem_ctx, child,
400 NDR_WINBIND_GET_DC_INFO, r,
401 winbindd_get_dc_info_recv, r,
402 (void *)cont, private_data);
405 static void ndr_child_get_dc_info_comapt_nt4(struct winbindd_domain *domain,
406 struct winbindd_cli_state *state,
407 struct winbind_get_dc_info *r)
409 const char *dcname_slash;
411 struct rpc_pipe_client *netlogon_pipe;
414 unsigned int orig_timeout;
415 struct winbindd_domain *req_domain;
417 DEBUG(3, ("Get DC name for '%s'\n", r->in.domain_name));
419 result = cm_connect_netlogon(domain, &netlogon_pipe);
421 if (!NT_STATUS_IS_OK(result)) {
422 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
423 r->out.result = WINBIND_STATUS_FOOBAR;
427 /* This call can take a long time - allow the server to time out.
428 35 seconds should do it. */
430 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
433 * if the requested domain name matches the current one
434 * we need to use GetDCName(), because GetAnyDCName() only
435 * works for trusted domains
437 req_domain = find_domain_from_name_noinit(r->in.domain_name);
438 if (req_domain == domain) {
439 result = rpccli_netr_GetDcName(netlogon_pipe,
446 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
453 /* And restore our original timeout. */
454 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
456 if (!NT_STATUS_IS_OK(result)) {
457 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
458 r->in.domain_name, nt_errstr(result)));
459 r->out.result = WINBIND_STATUS_FOOBAR;
463 if (!W_ERROR_IS_OK(werr)) {
464 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
465 r->in.domain_name, dos_errstr(werr)));
466 r->out.result = WINBIND_STATUS_FOOBAR;
478 r->out.dc_info->name = talloc_strdup(r, p);
479 if (!r->out.dc_info->name) {
480 r->out.result = WINBIND_STATUS_NO_MEMORY;
483 r->out.result = WINBIND_STATUS_OK;
486 void winbindd_ndr_domain_child_get_dc_info(struct winbindd_domain *domain,
487 struct winbindd_cli_state *state)
489 struct winbind_get_dc_info *r;
491 r = talloc_get_type_abort(state->c.ndr.r,
492 struct winbind_get_dc_info);
494 switch (*r->in.level) {
495 case WINBIND_DC_INFO_LEVEL_COMPAT_NT4:
496 ndr_child_get_dc_info_comapt_nt4(domain, state, r);
499 case WINBIND_DC_INFO_LEVEL_COMPAT_DS:
500 r->out.result = WINBIND_STATUS_INVALID_LEVEL;
504 r->out.result = WINBIND_STATUS_UNKNOWN_LEVEL;
508 struct sequence_state {
510 struct winbindd_cli_state *cli_state;
511 struct winbindd_domain *domain;
512 struct winbindd_request *request;
513 struct winbindd_response *response;
517 static void sequence_recv(void *private_data, bool success);
519 void winbindd_show_sequence(struct winbindd_cli_state *state)
521 struct sequence_state *seq;
523 /* Ensure null termination */
524 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
526 if (strlen(state->request.domain_name) > 0) {
527 struct winbindd_domain *domain;
528 domain = find_domain_from_name_noinit(
529 state->request.domain_name);
530 if (domain == NULL) {
531 request_error(state);
534 sendto_domain(state, domain);
538 /* Ask all domains in sequence, collect the results in sequence_recv */
540 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
542 DEBUG(0, ("talloc failed\n"));
543 request_error(state);
547 seq->mem_ctx = state->mem_ctx;
548 seq->cli_state = state;
549 seq->domain = domain_list();
550 if (seq->domain == NULL) {
551 DEBUG(0, ("domain list empty\n"));
552 request_error(state);
555 seq->request = TALLOC_ZERO_P(state->mem_ctx,
556 struct winbindd_request);
557 seq->response = TALLOC_ZERO_P(state->mem_ctx,
558 struct winbindd_response);
559 seq->extra_data = talloc_strdup(state->mem_ctx, "");
561 if ((seq->request == NULL) || (seq->response == NULL) ||
562 (seq->extra_data == NULL)) {
563 DEBUG(0, ("talloc failed\n"));
564 request_error(state);
568 seq->request->length = sizeof(*seq->request);
569 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
570 fstrcpy(seq->request->domain_name, seq->domain->name);
572 async_domain_request(state->mem_ctx, seq->domain,
573 seq->request, seq->response,
577 static void sequence_recv(void *private_data, bool success)
579 struct sequence_state *state =
580 (struct sequence_state *)private_data;
581 uint32 seq = DOM_SEQUENCE_NONE;
583 if ((success) && (state->response->result == WINBINDD_OK))
584 seq = state->response->data.sequence_number;
586 if (seq == DOM_SEQUENCE_NONE) {
587 state->extra_data = talloc_asprintf(state->mem_ctx,
588 "%s%s : DISCONNECTED\n",
590 state->domain->name);
592 state->extra_data = talloc_asprintf(state->mem_ctx,
595 state->domain->name, seq);
598 state->domain->sequence_number = seq;
600 state->domain = state->domain->next;
602 if (state->domain == NULL) {
603 struct winbindd_cli_state *cli_state = state->cli_state;
604 cli_state->response.length =
605 sizeof(cli_state->response) +
606 strlen(state->extra_data) + 1;
607 cli_state->response.extra_data.data =
608 SMB_STRDUP(state->extra_data);
609 request_ok(cli_state);
613 /* Ask the next domain */
614 fstrcpy(state->request->domain_name, state->domain->name);
615 async_domain_request(state->mem_ctx, state->domain,
616 state->request, state->response,
617 sequence_recv, state);
620 /* This is the child-only version of --sequence. It only allows for a single
621 * domain (ie "our" one) to be displayed. */
623 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
624 struct winbindd_cli_state *state)
626 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
628 /* Ensure null termination */
629 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
631 domain->methods->sequence_number(domain, &domain->sequence_number);
633 state->response.data.sequence_number =
634 domain->sequence_number;
639 struct domain_info_state {
640 struct winbindd_domain *domain;
641 struct winbindd_cli_state *cli_state;
644 static void domain_info_init_recv(void *private_data, bool success);
646 void winbindd_domain_info(struct winbindd_cli_state *state)
648 struct winbindd_domain *domain;
650 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
651 state->request.domain_name));
653 domain = find_domain_from_name_noinit(state->request.domain_name);
655 if (domain == NULL) {
656 DEBUG(3, ("Did not find domain [%s]\n",
657 state->request.domain_name));
658 request_error(state);
662 if (!domain->initialized) {
663 struct domain_info_state *istate;
665 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
666 if (istate == NULL) {
667 DEBUG(0, ("talloc failed\n"));
668 request_error(state);
672 istate->cli_state = state;
673 istate->domain = domain;
675 init_child_connection(domain, domain_info_init_recv, istate);
680 fstrcpy(state->response.data.domain_info.name,
682 fstrcpy(state->response.data.domain_info.alt_name,
684 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
686 state->response.data.domain_info.native_mode =
688 state->response.data.domain_info.active_directory =
689 domain->active_directory;
690 state->response.data.domain_info.primary =
696 static void domain_info_init_recv(void *private_data, bool success)
698 struct domain_info_state *istate =
699 (struct domain_info_state *)private_data;
700 struct winbindd_cli_state *state = istate->cli_state;
701 struct winbindd_domain *domain = istate->domain;
703 DEBUG(10, ("Got back from child init: %d\n", success));
705 if ((!success) || (!domain->initialized)) {
706 DEBUG(5, ("Could not init child for domain %s\n",
708 request_error(state);
712 fstrcpy(state->response.data.domain_info.name,
714 fstrcpy(state->response.data.domain_info.alt_name,
716 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
718 state->response.data.domain_info.native_mode =
720 state->response.data.domain_info.active_directory =
721 domain->active_directory;
722 state->response.data.domain_info.primary =
728 void winbindd_ping(struct winbindd_cli_state *state)
730 if (lp_parm_bool(-1, "winbindd", "ping_our_domain", False)) {
731 sendto_domain(state, find_our_domain());
735 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
739 enum winbindd_result winbindd_dual_ping(struct winbindd_domain *domain,
740 struct winbindd_cli_state *state)
742 DEBUG(3, ("[%5lu]: (dual) ping\n", (unsigned long)state->pid));
746 /* List various tidbits of information */
748 void winbindd_info(struct winbindd_cli_state *state)
751 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
753 state->response.data.info.winbind_separator = *lp_winbind_separator();
754 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
758 /* Tell the client the current interface version */
760 void winbindd_interface_version(struct winbindd_cli_state *state)
762 DEBUG(3, ("[%5lu]: request interface version\n",
763 (unsigned long)state->pid));
765 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
769 /* What domain are we a member of? */
771 void winbindd_domain_name(struct winbindd_cli_state *state)
773 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
775 fstrcpy(state->response.data.domain_name, lp_workgroup());
779 /* What's my name again? */
781 void winbindd_netbios_name(struct winbindd_cli_state *state)
783 DEBUG(3, ("[%5lu]: request netbios name\n",
784 (unsigned long)state->pid));
786 fstrcpy(state->response.data.netbios_name, global_myname());
790 /* Where can I find the privilaged pipe? */
792 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
795 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
796 (unsigned long)state->pid));
798 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
799 if (!state->response.extra_data.data) {
800 DEBUG(0, ("malloc failed\n"));
801 request_error(state);
805 /* must add one to length to copy the 0 for string termination */
806 state->response.length +=
807 strlen((char *)state->response.extra_data.data) + 1;