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 set_auth_errors(state->response, result);
91 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
92 state->response->data.auth.nt_status_string));
94 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
97 /* Helpers for listing user and group names */
99 const char *ent_type_strings[] = {"users",
102 static const char *get_ent_type_string(enum ent_type type)
104 return ent_type_strings[type];
107 struct listent_state {
109 struct winbindd_cli_state *cli_state;
113 uint32_t extra_data_len;
116 static void listent_recv(void *private_data, bool success, fstring dom_name,
119 /* List domain users/groups without mapping to unix ids */
120 void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type)
122 struct winbindd_domain *domain;
123 const char *which_domain;
124 struct listent_state *ent_state;
126 DEBUG(3, ("[%5lu]: list %s\n", (unsigned long)state->pid,
127 get_ent_type_string(type)));
129 /* Ensure null termination */
130 state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
131 which_domain = state->request->domain_name;
133 /* Initialize listent_state */
134 ent_state = TALLOC_P(state->mem_ctx, struct listent_state);
135 if (ent_state == NULL) {
136 DEBUG(0, ("talloc failed\n"));
137 request_error(state);
141 ent_state->mem_ctx = state->mem_ctx;
142 ent_state->cli_state = state;
143 ent_state->type = type;
144 ent_state->domain_count = 0;
145 ent_state->extra_data = NULL;
146 ent_state->extra_data_len = 0;
148 /* Must count the full list of expected domains before we request data
149 * from any of them. Otherwise it's possible for a connection to the
150 * first domain to fail, call listent_recv(), and return to the
151 * client without checking any other domains. */
152 for (domain = domain_list(); domain; domain = domain->next) {
153 /* if we have a domain name restricting the request and this
154 one in the list doesn't match, then just bypass the remainder
156 if ( *which_domain && !strequal(which_domain, domain->name) )
159 ent_state->domain_count++;
162 /* Make sure we're enumerating at least one domain */
163 if (!ent_state->domain_count) {
168 /* Enumerate list of trusted domains and request user/group list from
170 for (domain = domain_list(); domain; domain = domain->next) {
171 if ( *which_domain && !strequal(which_domain, domain->name) )
174 winbindd_listent_async(state->mem_ctx, domain,
175 listent_recv, ent_state, type);
179 static void listent_recv(void *private_data, bool success, fstring dom_name,
182 /* extra_data comes to us as a '\0' terminated string of comma
183 separated users or groups */
184 struct listent_state *state = talloc_get_type_abort(
185 private_data, struct listent_state);
187 /* Append users/groups from one domain onto the whole list */
189 DEBUG(5, ("listent_recv: %s returned %s.\n",
190 dom_name, get_ent_type_string(state->type)));
191 if (!state->extra_data)
192 state->extra_data = talloc_asprintf(state->mem_ctx,
195 state->extra_data = talloc_asprintf_append(
198 /* Add one for the '\0' and each additional ',' */
199 state->extra_data_len += strlen(extra_data) + 1;
202 DEBUG(5, ("listent_recv: %s returned no %s.\n",
203 dom_name, get_ent_type_string(state->type)));
206 if (--state->domain_count)
207 /* Still waiting for some child domains to return */
210 /* Return list of all users/groups to the client */
211 if (state->extra_data) {
212 state->cli_state->response->extra_data.data = state->extra_data;
213 state->cli_state->response->length += state->extra_data_len;
216 request_ok(state->cli_state);
219 /* Constants and helper functions for determining domain trust types */
228 const char *trust_type_strings[] = {"External",
233 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
235 if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)
237 else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
239 else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
240 ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
245 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
247 return trust_type_strings[get_trust_type(domain)];
250 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
252 return (domain->trust_flags == 0x0) ||
253 ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
254 NETR_TRUST_FLAG_IN_FOREST) ||
255 ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
256 NETR_TRUST_FLAG_INBOUND);
259 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
261 return (domain->trust_flags == 0x0) ||
262 ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
263 NETR_TRUST_FLAG_IN_FOREST) ||
264 ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
265 NETR_TRUST_FLAG_OUTBOUND);
268 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
270 if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||
271 (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
272 (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
277 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
279 struct winbindd_tdc_domain *dom_list = NULL;
280 struct winbindd_tdc_domain *d = NULL;
281 size_t num_domains = 0;
282 int extra_data_len = 0;
283 char *extra_data = NULL;
286 DEBUG(3, ("[%5lu]: list trusted domains\n",
287 (unsigned long)state->pid));
289 if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
290 request_error(state);
294 for ( i = 0; i < num_domains; i++ ) {
295 struct winbindd_domain *domain;
296 bool is_online = true;
299 domain = find_domain_from_name_noinit(d->domain_name);
301 is_online = domain->online;
305 extra_data = talloc_asprintf(state->mem_ctx,
306 "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
308 d->dns_name ? d->dns_name : d->domain_name,
309 sid_string_talloc(state->mem_ctx, &d->sid),
310 get_trust_type_string(d),
311 trust_is_transitive(d) ? "Yes" : "No",
312 trust_is_inbound(d) ? "Yes" : "No",
313 trust_is_outbound(d) ? "Yes" : "No",
314 is_online ? "Online" : "Offline" );
316 extra_data = talloc_asprintf(state->mem_ctx,
317 "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
320 d->dns_name ? d->dns_name : d->domain_name,
321 sid_string_talloc(state->mem_ctx, &d->sid),
322 get_trust_type_string(d),
323 trust_is_transitive(d) ? "Yes" : "No",
324 trust_is_inbound(d) ? "Yes" : "No",
325 trust_is_outbound(d) ? "Yes" : "No",
326 is_online ? "Online" : "Offline" );
331 if (extra_data != NULL) {
332 extra_data_len = strlen(extra_data);
335 if (extra_data_len > 0) {
336 state->response->extra_data.data = extra_data;
337 state->response->length += extra_data_len+1;
342 TALLOC_FREE( dom_list );
345 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
346 struct winbindd_cli_state *state)
348 uint32 i, num_domains;
349 char **names, **alt_names;
351 int extra_data_len = 0;
354 bool have_own_domain = False;
356 DEBUG(3, ("[%5lu]: list trusted domains\n",
357 (unsigned long)state->pid));
359 result = domain->methods->trusted_domains(domain, state->mem_ctx,
360 &num_domains, &names,
363 if (!NT_STATUS_IS_OK(result)) {
364 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
365 nt_errstr(result) ));
366 return WINBINDD_ERROR;
369 extra_data = talloc_strdup(state->mem_ctx, "");
372 extra_data = talloc_asprintf(
373 state->mem_ctx, "%s\\%s\\%s",
374 names[0], alt_names[0] ? alt_names[0] : names[0],
375 sid_string_talloc(state->mem_ctx, &sids[0]));
377 for (i=1; i<num_domains; i++)
378 extra_data = talloc_asprintf(
379 state->mem_ctx, "%s\n%s\\%s\\%s",
380 extra_data, names[i],
381 alt_names[i] ? alt_names[i] : names[i],
382 sid_string_talloc(state->mem_ctx, &sids[i]));
384 /* add our primary domain */
386 for (i=0; i<num_domains; i++) {
387 if (strequal(names[i], domain->name)) {
388 have_own_domain = True;
393 if (state->request->data.list_all_domains && !have_own_domain) {
394 extra_data = talloc_asprintf(
395 state->mem_ctx, "%s\n%s\\%s\\%s",
396 extra_data, domain->name,
397 domain->alt_name ? domain->alt_name : domain->name,
398 sid_string_talloc(state->mem_ctx, &domain->sid));
401 /* This is a bit excessive, but the extra data sooner or later will be
405 if (extra_data != NULL) {
406 extra_data_len = strlen(extra_data);
409 if (extra_data_len > 0) {
410 state->response->extra_data.data = extra_data;
411 state->response->length += extra_data_len+1;
417 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
418 struct winbindd_cli_state *state)
420 const char *dcname_slash = NULL;
422 struct rpc_pipe_client *netlogon_pipe;
425 unsigned int orig_timeout;
426 struct winbindd_domain *req_domain;
428 state->request->domain_name
429 [sizeof(state->request->domain_name)-1] = '\0';
431 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
432 state->request->domain_name));
434 result = cm_connect_netlogon(domain, &netlogon_pipe);
436 if (!NT_STATUS_IS_OK(result)) {
437 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
438 return WINBINDD_ERROR;
441 /* This call can take a long time - allow the server to time out.
442 35 seconds should do it. */
444 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
446 req_domain = find_domain_from_name_noinit(state->request->domain_name);
447 if (req_domain == domain) {
448 result = rpccli_netr_GetDcName(netlogon_pipe,
451 state->request->domain_name,
455 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
458 state->request->domain_name,
462 /* And restore our original timeout. */
463 rpccli_set_timeout(netlogon_pipe, orig_timeout);
465 if (!NT_STATUS_IS_OK(result)) {
466 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
467 state->request->domain_name, nt_errstr(result)));
468 return WINBINDD_ERROR;
471 if (!W_ERROR_IS_OK(werr)) {
472 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
473 state->request->domain_name, win_errstr(werr)));
474 return WINBINDD_ERROR;
485 fstrcpy(state->response->data.dc_name, p);
489 /* This is the child-only version of --sequence. It only allows for a single
490 * domain (ie "our" one) to be displayed. */
492 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
493 struct winbindd_cli_state *state)
495 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
497 /* Ensure null termination */
498 state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
500 domain->methods->sequence_number(domain, &domain->sequence_number);
502 state->response->data.sequence_number =
503 domain->sequence_number;
508 struct domain_info_state {
509 struct winbindd_domain *domain;
510 struct winbindd_cli_state *cli;
511 struct winbindd_request ping_request;
514 static void domain_info_done(struct tevent_req *req);
516 void winbindd_domain_info(struct winbindd_cli_state *cli)
518 struct domain_info_state *state;
519 struct winbindd_domain *domain;
520 struct tevent_req *req;
522 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
523 cli->request->domain_name));
525 domain = find_domain_from_name_noinit(cli->request->domain_name);
527 if (domain == NULL) {
528 DEBUG(3, ("Did not find domain [%s]\n",
529 cli->request->domain_name));
534 if (domain->initialized) {
535 fstrcpy(cli->response->data.domain_info.name,
537 fstrcpy(cli->response->data.domain_info.alt_name,
539 sid_to_fstring(cli->response->data.domain_info.sid,
541 cli->response->data.domain_info.native_mode =
543 cli->response->data.domain_info.active_directory =
544 domain->active_directory;
545 cli->response->data.domain_info.primary =
551 state = talloc_zero(cli->mem_ctx, struct domain_info_state);
553 DEBUG(0, ("talloc failed\n"));
559 state->domain = domain;
560 state->ping_request.cmd = WINBINDD_PING;
563 * Send a ping down. This implicitly initializes the domain.
566 req = wb_domain_request_send(state, winbind_event_context(),
567 domain, &state->ping_request);
569 DEBUG(3, ("wb_domain_request_send failed\n"));
572 tevent_req_set_callback(req, domain_info_done, state);
575 static void domain_info_done(struct tevent_req *req)
577 struct domain_info_state *state = tevent_req_callback_data(
578 req, struct domain_info_state);
579 struct winbindd_response *response;
582 ret = wb_domain_request_recv(req, req, &response, &err);
585 DEBUG(10, ("wb_domain_request failed: %s\n", strerror(errno)));
586 request_error(state->cli);
589 if (!state->domain->initialized) {
590 DEBUG(5, ("wb_domain_request did not initialize domain %s\n",
591 state->domain->name));
592 request_error(state->cli);
596 fstrcpy(state->cli->response->data.domain_info.name,
597 state->domain->name);
598 fstrcpy(state->cli->response->data.domain_info.alt_name,
599 state->domain->alt_name);
600 sid_to_fstring(state->cli->response->data.domain_info.sid,
601 &state->domain->sid);
603 state->cli->response->data.domain_info.native_mode =
604 state->domain->native_mode;
605 state->cli->response->data.domain_info.active_directory =
606 state->domain->active_directory;
607 state->cli->response->data.domain_info.primary =
608 state->domain->primary;
610 request_ok(state->cli);
613 /* List various tidbits of information */
615 void winbindd_info(struct winbindd_cli_state *state)
618 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
620 state->response->data.info.winbind_separator = *lp_winbind_separator();
621 fstrcpy(state->response->data.info.samba_version, samba_version_string());
625 /* Tell the client the current interface version */
627 void winbindd_interface_version(struct winbindd_cli_state *state)
629 DEBUG(3, ("[%5lu]: request interface version\n",
630 (unsigned long)state->pid));
632 state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
636 /* What domain are we a member of? */
638 void winbindd_domain_name(struct winbindd_cli_state *state)
640 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
642 fstrcpy(state->response->data.domain_name, lp_workgroup());
646 /* What's my name again? */
648 void winbindd_netbios_name(struct winbindd_cli_state *state)
650 DEBUG(3, ("[%5lu]: request netbios name\n",
651 (unsigned long)state->pid));
653 fstrcpy(state->response->data.netbios_name, global_myname());
657 /* Where can I find the privilaged pipe? */
659 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
662 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
663 (unsigned long)state->pid));
665 priv_dir = get_winbind_priv_pipe_dir();
666 state->response->extra_data.data = talloc_move(state->mem_ctx,
669 /* must add one to length to copy the 0 for string termination */
670 state->response->length +=
671 strlen((char *)state->response->extra_data.data) + 1;