mapping.tdb: fix creation of entries with GROUP_PREFIX
[Samba.git] / source / winbindd / winbindd_misc.c
blob93986d174e54b8e2682ea04dcc143ac35bd04ba1
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 d = &dom_list[i];
177 if ( !extra_data ) {
178 extra_data = talloc_asprintf(state->mem_ctx,
179 "%s\\%s\\%s\\%s\\%s\\%s\\%s",
180 d->domain_name,
181 d->dns_name ? d->dns_name : d->domain_name,
182 sid_string_talloc(state->mem_ctx, &d->sid),
183 get_trust_type_string(d),
184 trust_is_transitive(d) ? "Yes" : "No",
185 trust_is_inbound(d) ? "Yes" : "No",
186 trust_is_outbound(d) ? "Yes" : "No");
187 } else {
188 extra_data = talloc_asprintf(state->mem_ctx,
189 "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s",
190 extra_data,
191 d->domain_name,
192 d->dns_name ? d->dns_name : d->domain_name,
193 sid_string_talloc(state->mem_ctx, &d->sid),
194 get_trust_type_string(d),
195 trust_is_transitive(d) ? "Yes" : "No",
196 trust_is_inbound(d) ? "Yes" : "No",
197 trust_is_outbound(d) ? "Yes" : "No");
201 extra_data_len = 0;
202 if (extra_data != NULL) {
203 extra_data_len = strlen(extra_data);
206 if (extra_data_len > 0) {
207 state->response.extra_data.data = SMB_STRDUP(extra_data);
208 state->response.length += extra_data_len+1;
211 request_ok(state);
212 done:
213 TALLOC_FREE( dom_list );
214 TALLOC_FREE( extra_data );
217 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
218 struct winbindd_cli_state *state)
220 uint32 i, num_domains;
221 char **names, **alt_names;
222 DOM_SID *sids;
223 int extra_data_len = 0;
224 char *extra_data;
225 NTSTATUS result;
226 bool have_own_domain = False;
228 DEBUG(3, ("[%5lu]: list trusted domains\n",
229 (unsigned long)state->pid));
231 result = domain->methods->trusted_domains(domain, state->mem_ctx,
232 &num_domains, &names,
233 &alt_names, &sids);
235 if (!NT_STATUS_IS_OK(result)) {
236 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
237 nt_errstr(result) ));
238 return WINBINDD_ERROR;
241 extra_data = talloc_strdup(state->mem_ctx, "");
243 if (num_domains > 0)
244 extra_data = talloc_asprintf(
245 state->mem_ctx, "%s\\%s\\%s",
246 names[0], alt_names[0] ? alt_names[0] : names[0],
247 sid_string_talloc(state->mem_ctx, &sids[0]));
249 for (i=1; i<num_domains; i++)
250 extra_data = talloc_asprintf(
251 state->mem_ctx, "%s\n%s\\%s\\%s",
252 extra_data, names[i],
253 alt_names[i] ? alt_names[i] : names[i],
254 sid_string_talloc(state->mem_ctx, &sids[i]));
256 /* add our primary domain */
258 for (i=0; i<num_domains; i++) {
259 if (strequal(names[i], domain->name)) {
260 have_own_domain = True;
261 break;
265 if (state->request.data.list_all_domains && !have_own_domain) {
266 extra_data = talloc_asprintf(
267 state->mem_ctx, "%s\n%s\\%s\\%s",
268 extra_data, domain->name,
269 domain->alt_name ? domain->alt_name : domain->name,
270 sid_string_talloc(state->mem_ctx, &domain->sid));
273 /* This is a bit excessive, but the extra data sooner or later will be
274 talloc'ed */
276 extra_data_len = 0;
277 if (extra_data != NULL) {
278 extra_data_len = strlen(extra_data);
281 if (extra_data_len > 0) {
282 state->response.extra_data.data = SMB_STRDUP(extra_data);
283 state->response.length += extra_data_len+1;
286 return WINBINDD_OK;
289 void winbindd_getdcname(struct winbindd_cli_state *state)
291 struct winbindd_domain *domain;
293 state->request.domain_name
294 [sizeof(state->request.domain_name)-1] = '\0';
296 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
297 state->request.domain_name));
299 domain = find_domain_from_name_noinit(state->request.domain_name);
300 if (domain && domain->internal) {
301 fstrcpy(state->response.data.dc_name, global_myname());
302 request_ok(state);
303 return;
306 sendto_domain(state, find_our_domain());
309 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
310 struct winbindd_cli_state *state)
312 const char *dcname_slash = NULL;
313 const char *p;
314 struct rpc_pipe_client *netlogon_pipe;
315 NTSTATUS result;
316 WERROR werr;
317 unsigned int orig_timeout;
318 struct winbindd_domain *req_domain;
320 state->request.domain_name
321 [sizeof(state->request.domain_name)-1] = '\0';
323 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
324 state->request.domain_name));
326 result = cm_connect_netlogon(domain, &netlogon_pipe);
328 if (!NT_STATUS_IS_OK(result)) {
329 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
330 return WINBINDD_ERROR;
333 /* This call can take a long time - allow the server to time out.
334 35 seconds should do it. */
336 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
338 req_domain = find_domain_from_name_noinit(state->request.domain_name);
339 if (req_domain == domain) {
340 result = rpccli_netr_GetDcName(netlogon_pipe,
341 state->mem_ctx,
342 domain->dcname,
343 state->request.domain_name,
344 &dcname_slash,
345 &werr);
346 } else {
347 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
348 state->mem_ctx,
349 domain->dcname,
350 state->request.domain_name,
351 &dcname_slash,
352 &werr);
354 /* And restore our original timeout. */
355 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
357 if (!NT_STATUS_IS_OK(result)) {
358 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
359 state->request.domain_name, nt_errstr(result)));
360 return WINBINDD_ERROR;
363 if (!W_ERROR_IS_OK(werr)) {
364 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
365 state->request.domain_name, dos_errstr(werr)));
366 return WINBINDD_ERROR;
369 p = dcname_slash;
370 if (*p == '\\') {
371 p+=1;
373 if (*p == '\\') {
374 p+=1;
377 fstrcpy(state->response.data.dc_name, p);
378 return WINBINDD_OK;
381 struct sequence_state {
382 TALLOC_CTX *mem_ctx;
383 struct winbindd_cli_state *cli_state;
384 struct winbindd_domain *domain;
385 struct winbindd_request *request;
386 struct winbindd_response *response;
387 char *extra_data;
390 static void sequence_recv(void *private_data, bool success);
392 void winbindd_show_sequence(struct winbindd_cli_state *state)
394 struct sequence_state *seq;
396 /* Ensure null termination */
397 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
399 if (strlen(state->request.domain_name) > 0) {
400 struct winbindd_domain *domain;
401 domain = find_domain_from_name_noinit(
402 state->request.domain_name);
403 if (domain == NULL) {
404 request_error(state);
405 return;
407 sendto_domain(state, domain);
408 return;
411 /* Ask all domains in sequence, collect the results in sequence_recv */
413 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
414 if (seq == NULL) {
415 DEBUG(0, ("talloc failed\n"));
416 request_error(state);
417 return;
420 seq->mem_ctx = state->mem_ctx;
421 seq->cli_state = state;
422 seq->domain = domain_list();
423 if (seq->domain == NULL) {
424 DEBUG(0, ("domain list empty\n"));
425 request_error(state);
426 return;
428 seq->request = TALLOC_ZERO_P(state->mem_ctx,
429 struct winbindd_request);
430 seq->response = TALLOC_ZERO_P(state->mem_ctx,
431 struct winbindd_response);
432 seq->extra_data = talloc_strdup(state->mem_ctx, "");
434 if ((seq->request == NULL) || (seq->response == NULL) ||
435 (seq->extra_data == NULL)) {
436 DEBUG(0, ("talloc failed\n"));
437 request_error(state);
438 return;
441 seq->request->length = sizeof(*seq->request);
442 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
443 fstrcpy(seq->request->domain_name, seq->domain->name);
445 async_domain_request(state->mem_ctx, seq->domain,
446 seq->request, seq->response,
447 sequence_recv, seq);
450 static void sequence_recv(void *private_data, bool success)
452 struct sequence_state *state =
453 (struct sequence_state *)private_data;
454 uint32 seq = DOM_SEQUENCE_NONE;
456 if ((success) && (state->response->result == WINBINDD_OK))
457 seq = state->response->data.sequence_number;
459 if (seq == DOM_SEQUENCE_NONE) {
460 state->extra_data = talloc_asprintf(state->mem_ctx,
461 "%s%s : DISCONNECTED\n",
462 state->extra_data,
463 state->domain->name);
464 } else {
465 state->extra_data = talloc_asprintf(state->mem_ctx,
466 "%s%s : %d\n",
467 state->extra_data,
468 state->domain->name, seq);
471 state->domain->sequence_number = seq;
473 state->domain = state->domain->next;
475 if (state->domain == NULL) {
476 struct winbindd_cli_state *cli_state = state->cli_state;
477 cli_state->response.length =
478 sizeof(cli_state->response) +
479 strlen(state->extra_data) + 1;
480 cli_state->response.extra_data.data =
481 SMB_STRDUP(state->extra_data);
482 request_ok(cli_state);
483 return;
486 /* Ask the next domain */
487 fstrcpy(state->request->domain_name, state->domain->name);
488 async_domain_request(state->mem_ctx, state->domain,
489 state->request, state->response,
490 sequence_recv, state);
493 /* This is the child-only version of --sequence. It only allows for a single
494 * domain (ie "our" one) to be displayed. */
496 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
497 struct winbindd_cli_state *state)
499 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
501 /* Ensure null termination */
502 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
504 domain->methods->sequence_number(domain, &domain->sequence_number);
506 state->response.data.sequence_number =
507 domain->sequence_number;
509 return WINBINDD_OK;
512 struct domain_info_state {
513 struct winbindd_domain *domain;
514 struct winbindd_cli_state *cli_state;
517 static void domain_info_init_recv(void *private_data, bool success);
519 void winbindd_domain_info(struct winbindd_cli_state *state)
521 struct winbindd_domain *domain;
523 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
524 state->request.domain_name));
526 domain = find_domain_from_name_noinit(state->request.domain_name);
528 if (domain == NULL) {
529 DEBUG(3, ("Did not find domain [%s]\n",
530 state->request.domain_name));
531 request_error(state);
532 return;
535 if (!domain->initialized) {
536 struct domain_info_state *istate;
538 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
539 if (istate == NULL) {
540 DEBUG(0, ("talloc failed\n"));
541 request_error(state);
542 return;
545 istate->cli_state = state;
546 istate->domain = domain;
548 init_child_connection(domain, domain_info_init_recv, istate);
550 return;
553 fstrcpy(state->response.data.domain_info.name,
554 domain->name);
555 fstrcpy(state->response.data.domain_info.alt_name,
556 domain->alt_name);
557 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
559 state->response.data.domain_info.native_mode =
560 domain->native_mode;
561 state->response.data.domain_info.active_directory =
562 domain->active_directory;
563 state->response.data.domain_info.primary =
564 domain->primary;
566 request_ok(state);
569 static void domain_info_init_recv(void *private_data, bool success)
571 struct domain_info_state *istate =
572 (struct domain_info_state *)private_data;
573 struct winbindd_cli_state *state = istate->cli_state;
574 struct winbindd_domain *domain = istate->domain;
576 DEBUG(10, ("Got back from child init: %d\n", success));
578 if ((!success) || (!domain->initialized)) {
579 DEBUG(5, ("Could not init child for domain %s\n",
580 domain->name));
581 request_error(state);
582 return;
585 fstrcpy(state->response.data.domain_info.name,
586 domain->name);
587 fstrcpy(state->response.data.domain_info.alt_name,
588 domain->alt_name);
589 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
591 state->response.data.domain_info.native_mode =
592 domain->native_mode;
593 state->response.data.domain_info.active_directory =
594 domain->active_directory;
595 state->response.data.domain_info.primary =
596 domain->primary;
598 request_ok(state);
601 void winbindd_ping(struct winbindd_cli_state *state)
603 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
604 request_ok(state);
607 /* List various tidbits of information */
609 void winbindd_info(struct winbindd_cli_state *state)
612 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
614 state->response.data.info.winbind_separator = *lp_winbind_separator();
615 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
616 request_ok(state);
619 /* Tell the client the current interface version */
621 void winbindd_interface_version(struct winbindd_cli_state *state)
623 DEBUG(3, ("[%5lu]: request interface version\n",
624 (unsigned long)state->pid));
626 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
627 request_ok(state);
630 /* What domain are we a member of? */
632 void winbindd_domain_name(struct winbindd_cli_state *state)
634 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
636 fstrcpy(state->response.data.domain_name, lp_workgroup());
637 request_ok(state);
640 /* What's my name again? */
642 void winbindd_netbios_name(struct winbindd_cli_state *state)
644 DEBUG(3, ("[%5lu]: request netbios name\n",
645 (unsigned long)state->pid));
647 fstrcpy(state->response.data.netbios_name, global_myname());
648 request_ok(state);
651 /* Where can I find the privilaged pipe? */
653 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
656 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
657 (unsigned long)state->pid));
659 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
660 if (!state->response.extra_data.data) {
661 DEBUG(0, ("malloc failed\n"));
662 request_error(state);
663 return;
666 /* must add one to length to copy the 0 for string termination */
667 state->response.length +=
668 strlen((char *)state->response.extra_data.data) + 1;
670 request_ok(state);