VERSION: Raise version number to 3.2.0rc2.
[Samba.git] / source / winbindd / winbindd_misc.c
blobf63aa1689044770e7cf79323b53aadd8a6f6b6c2
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 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/>.
23 #include "includes.h"
24 #include "winbindd.h"
26 #undef DBGC_CLASS
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;
43 int num_retries = 0;
44 struct winbindd_domain *contact_domain;
46 DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
48 /* Get trust account password */
50 again:
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"));
66 goto done;
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. */
74 #define MAX_RETRIES 8
76 if ((num_retries < MAX_RETRIES) &&
77 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
78 num_retries++;
79 goto again;
82 /* Pass back result code - zero for success, other values for
83 specific failures. */
85 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
86 "good" : "bad"));
88 done:
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 */
102 enum trust_type {
103 EXTERNAL = 0,
104 FOREST,
105 IN_FOREST,
106 NONE,
109 const char *trust_type_strings[] = {"External",
110 "Forest",
111 "In Forest",
112 "None"};
114 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
116 if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)
117 return EXTERNAL;
118 else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
119 return FOREST;
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))
122 return IN_FOREST;
123 return NONE;
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))
154 return False;
155 return True;
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;
165 int i = 0;
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);
172 goto done;
175 for ( i = 0; i < num_domains; i++ ) {
176 struct winbindd_domain *domain;
177 bool is_online = true;
179 d = &dom_list[i];
180 domain = find_domain_from_name_noinit(d->domain_name);
181 if (domain) {
182 is_online = domain->online;
185 if ( !extra_data ) {
186 extra_data = talloc_asprintf(state->mem_ctx,
187 "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
188 d->domain_name,
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" );
196 } else {
197 extra_data = talloc_asprintf(state->mem_ctx,
198 "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
199 extra_data,
200 d->domain_name,
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" );
211 extra_data_len = 0;
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;
221 request_ok(state);
222 done:
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;
232 DOM_SID *sids;
233 int extra_data_len = 0;
234 char *extra_data;
235 NTSTATUS result;
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,
243 &alt_names, &sids);
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, "");
253 if (num_domains > 0)
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;
271 break;
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
284 talloc'ed */
286 extra_data_len = 0;
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;
296 return WINBINDD_OK;
299 void winbindd_getdcname(struct winbindd_cli_state *state)
301 struct winbindd_domain *domain;
303 state->request.domain_name
304 [sizeof(state->request.domain_name)-1] = '\0';
306 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
307 state->request.domain_name));
309 domain = find_domain_from_name_noinit(state->request.domain_name);
310 if (domain && domain->internal) {
311 fstrcpy(state->response.data.dc_name, global_myname());
312 request_ok(state);
313 return;
316 sendto_domain(state, find_our_domain());
319 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
320 struct winbindd_cli_state *state)
322 const char *dcname_slash = NULL;
323 const char *p;
324 struct rpc_pipe_client *netlogon_pipe;
325 NTSTATUS result;
326 WERROR werr;
327 unsigned int orig_timeout;
328 struct winbindd_domain *req_domain;
330 state->request.domain_name
331 [sizeof(state->request.domain_name)-1] = '\0';
333 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
334 state->request.domain_name));
336 result = cm_connect_netlogon(domain, &netlogon_pipe);
338 if (!NT_STATUS_IS_OK(result)) {
339 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
340 return WINBINDD_ERROR;
343 /* This call can take a long time - allow the server to time out.
344 35 seconds should do it. */
346 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
348 req_domain = find_domain_from_name_noinit(state->request.domain_name);
349 if (req_domain == domain) {
350 result = rpccli_netr_GetDcName(netlogon_pipe,
351 state->mem_ctx,
352 domain->dcname,
353 state->request.domain_name,
354 &dcname_slash,
355 &werr);
356 } else {
357 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
358 state->mem_ctx,
359 domain->dcname,
360 state->request.domain_name,
361 &dcname_slash,
362 &werr);
364 /* And restore our original timeout. */
365 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
367 if (!NT_STATUS_IS_OK(result)) {
368 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
369 state->request.domain_name, nt_errstr(result)));
370 return WINBINDD_ERROR;
373 if (!W_ERROR_IS_OK(werr)) {
374 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
375 state->request.domain_name, dos_errstr(werr)));
376 return WINBINDD_ERROR;
379 p = dcname_slash;
380 if (*p == '\\') {
381 p+=1;
383 if (*p == '\\') {
384 p+=1;
387 fstrcpy(state->response.data.dc_name, p);
388 return WINBINDD_OK;
391 struct sequence_state {
392 TALLOC_CTX *mem_ctx;
393 struct winbindd_cli_state *cli_state;
394 struct winbindd_domain *domain;
395 struct winbindd_request *request;
396 struct winbindd_response *response;
397 char *extra_data;
400 static void sequence_recv(void *private_data, bool success);
402 void winbindd_show_sequence(struct winbindd_cli_state *state)
404 struct sequence_state *seq;
406 /* Ensure null termination */
407 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
409 if (strlen(state->request.domain_name) > 0) {
410 struct winbindd_domain *domain;
411 domain = find_domain_from_name_noinit(
412 state->request.domain_name);
413 if (domain == NULL) {
414 request_error(state);
415 return;
417 sendto_domain(state, domain);
418 return;
421 /* Ask all domains in sequence, collect the results in sequence_recv */
423 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
424 if (seq == NULL) {
425 DEBUG(0, ("talloc failed\n"));
426 request_error(state);
427 return;
430 seq->mem_ctx = state->mem_ctx;
431 seq->cli_state = state;
432 seq->domain = domain_list();
433 if (seq->domain == NULL) {
434 DEBUG(0, ("domain list empty\n"));
435 request_error(state);
436 return;
438 seq->request = TALLOC_ZERO_P(state->mem_ctx,
439 struct winbindd_request);
440 seq->response = TALLOC_ZERO_P(state->mem_ctx,
441 struct winbindd_response);
442 seq->extra_data = talloc_strdup(state->mem_ctx, "");
444 if ((seq->request == NULL) || (seq->response == NULL) ||
445 (seq->extra_data == NULL)) {
446 DEBUG(0, ("talloc failed\n"));
447 request_error(state);
448 return;
451 seq->request->length = sizeof(*seq->request);
452 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
453 fstrcpy(seq->request->domain_name, seq->domain->name);
455 async_domain_request(state->mem_ctx, seq->domain,
456 seq->request, seq->response,
457 sequence_recv, seq);
460 static void sequence_recv(void *private_data, bool success)
462 struct sequence_state *state =
463 (struct sequence_state *)private_data;
464 uint32 seq = DOM_SEQUENCE_NONE;
466 if ((success) && (state->response->result == WINBINDD_OK))
467 seq = state->response->data.sequence_number;
469 if (seq == DOM_SEQUENCE_NONE) {
470 state->extra_data = talloc_asprintf(state->mem_ctx,
471 "%s%s : DISCONNECTED\n",
472 state->extra_data,
473 state->domain->name);
474 } else {
475 state->extra_data = talloc_asprintf(state->mem_ctx,
476 "%s%s : %d\n",
477 state->extra_data,
478 state->domain->name, seq);
481 state->domain->sequence_number = seq;
483 state->domain = state->domain->next;
485 if (state->domain == NULL) {
486 struct winbindd_cli_state *cli_state = state->cli_state;
487 cli_state->response.length =
488 sizeof(cli_state->response) +
489 strlen(state->extra_data) + 1;
490 cli_state->response.extra_data.data =
491 SMB_STRDUP(state->extra_data);
492 request_ok(cli_state);
493 return;
496 /* Ask the next domain */
497 fstrcpy(state->request->domain_name, state->domain->name);
498 async_domain_request(state->mem_ctx, state->domain,
499 state->request, state->response,
500 sequence_recv, state);
503 /* This is the child-only version of --sequence. It only allows for a single
504 * domain (ie "our" one) to be displayed. */
506 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
507 struct winbindd_cli_state *state)
509 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
511 /* Ensure null termination */
512 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
514 domain->methods->sequence_number(domain, &domain->sequence_number);
516 state->response.data.sequence_number =
517 domain->sequence_number;
519 return WINBINDD_OK;
522 struct domain_info_state {
523 struct winbindd_domain *domain;
524 struct winbindd_cli_state *cli_state;
527 static void domain_info_init_recv(void *private_data, bool success);
529 void winbindd_domain_info(struct winbindd_cli_state *state)
531 struct winbindd_domain *domain;
533 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
534 state->request.domain_name));
536 domain = find_domain_from_name_noinit(state->request.domain_name);
538 if (domain == NULL) {
539 DEBUG(3, ("Did not find domain [%s]\n",
540 state->request.domain_name));
541 request_error(state);
542 return;
545 if (!domain->initialized) {
546 struct domain_info_state *istate;
548 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
549 if (istate == NULL) {
550 DEBUG(0, ("talloc failed\n"));
551 request_error(state);
552 return;
555 istate->cli_state = state;
556 istate->domain = domain;
558 init_child_connection(domain, domain_info_init_recv, istate);
560 return;
563 fstrcpy(state->response.data.domain_info.name,
564 domain->name);
565 fstrcpy(state->response.data.domain_info.alt_name,
566 domain->alt_name);
567 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
569 state->response.data.domain_info.native_mode =
570 domain->native_mode;
571 state->response.data.domain_info.active_directory =
572 domain->active_directory;
573 state->response.data.domain_info.primary =
574 domain->primary;
576 request_ok(state);
579 static void domain_info_init_recv(void *private_data, bool success)
581 struct domain_info_state *istate =
582 (struct domain_info_state *)private_data;
583 struct winbindd_cli_state *state = istate->cli_state;
584 struct winbindd_domain *domain = istate->domain;
586 DEBUG(10, ("Got back from child init: %d\n", success));
588 if ((!success) || (!domain->initialized)) {
589 DEBUG(5, ("Could not init child for domain %s\n",
590 domain->name));
591 request_error(state);
592 return;
595 fstrcpy(state->response.data.domain_info.name,
596 domain->name);
597 fstrcpy(state->response.data.domain_info.alt_name,
598 domain->alt_name);
599 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
601 state->response.data.domain_info.native_mode =
602 domain->native_mode;
603 state->response.data.domain_info.active_directory =
604 domain->active_directory;
605 state->response.data.domain_info.primary =
606 domain->primary;
608 request_ok(state);
611 void winbindd_ping(struct winbindd_cli_state *state)
613 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
614 request_ok(state);
617 /* List various tidbits of information */
619 void winbindd_info(struct winbindd_cli_state *state)
622 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
624 state->response.data.info.winbind_separator = *lp_winbind_separator();
625 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
626 request_ok(state);
629 /* Tell the client the current interface version */
631 void winbindd_interface_version(struct winbindd_cli_state *state)
633 DEBUG(3, ("[%5lu]: request interface version\n",
634 (unsigned long)state->pid));
636 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
637 request_ok(state);
640 /* What domain are we a member of? */
642 void winbindd_domain_name(struct winbindd_cli_state *state)
644 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
646 fstrcpy(state->response.data.domain_name, lp_workgroup());
647 request_ok(state);
650 /* What's my name again? */
652 void winbindd_netbios_name(struct winbindd_cli_state *state)
654 DEBUG(3, ("[%5lu]: request netbios name\n",
655 (unsigned long)state->pid));
657 fstrcpy(state->response.data.netbios_name, global_myname());
658 request_ok(state);
661 /* Where can I find the privilaged pipe? */
663 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
666 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
667 (unsigned long)state->pid));
669 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
670 if (!state->response.extra_data.data) {
671 DEBUG(0, ("malloc failed\n"));
672 request_error(state);
673 return;
676 /* must add one to length to copy the 0 for string termination */
677 state->response.length +=
678 strlen((char *)state->response.extra_data.data) + 1;
680 request_ok(state);