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;
239 struct winbindd_domain *req_domain;
241 state->request.domain_name
242 [sizeof(state->request.domain_name)-1] = '\0';
244 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
245 state->request.domain_name));
247 result = cm_connect_netlogon(domain, &netlogon_pipe);
249 if (!NT_STATUS_IS_OK(result)) {
250 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
251 return WINBINDD_ERROR;
254 /* This call can take a long time - allow the server to time out.
255 35 seconds should do it. */
257 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
259 req_domain = find_domain_from_name_noinit(state->request.domain_name);
260 if (req_domain == domain) {
261 werr = rpccli_netlogon_getdcname(netlogon_pipe, state->mem_ctx,
263 state->request.domain_name,
266 werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx,
268 state->request.domain_name,
271 /* And restore our original timeout. */
272 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
274 if (!W_ERROR_IS_OK(werr)) {
275 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
276 state->request.domain_name, dos_errstr(werr)));
277 return WINBINDD_ERROR;
288 fstrcpy(state->response.data.dc_name, p);
292 struct sequence_state {
294 struct winbindd_cli_state *cli_state;
295 struct winbindd_domain *domain;
296 struct winbindd_request *request;
297 struct winbindd_response *response;
301 static void sequence_recv(void *private_data, BOOL success);
303 void winbindd_show_sequence(struct winbindd_cli_state *state)
305 struct sequence_state *seq;
307 /* Ensure null termination */
308 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
310 if (strlen(state->request.domain_name) > 0) {
311 struct winbindd_domain *domain;
312 domain = find_domain_from_name_noinit(
313 state->request.domain_name);
314 if (domain == NULL) {
315 request_error(state);
318 sendto_domain(state, domain);
322 /* Ask all domains in sequence, collect the results in sequence_recv */
324 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
326 DEBUG(0, ("talloc failed\n"));
327 request_error(state);
331 seq->mem_ctx = state->mem_ctx;
332 seq->cli_state = state;
333 seq->domain = domain_list();
334 if (seq->domain == NULL) {
335 DEBUG(0, ("domain list empty\n"));
336 request_error(state);
339 seq->request = TALLOC_ZERO_P(state->mem_ctx,
340 struct winbindd_request);
341 seq->response = TALLOC_ZERO_P(state->mem_ctx,
342 struct winbindd_response);
343 seq->extra_data = talloc_strdup(state->mem_ctx, "");
345 if ((seq->request == NULL) || (seq->response == NULL) ||
346 (seq->extra_data == NULL)) {
347 DEBUG(0, ("talloc failed\n"));
348 request_error(state);
352 seq->request->length = sizeof(*seq->request);
353 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
354 fstrcpy(seq->request->domain_name, seq->domain->name);
356 async_domain_request(state->mem_ctx, seq->domain,
357 seq->request, seq->response,
361 static void sequence_recv(void *private_data, BOOL success)
363 struct sequence_state *state =
364 (struct sequence_state *)private_data;
365 uint32 seq = DOM_SEQUENCE_NONE;
367 if ((success) && (state->response->result == WINBINDD_OK))
368 seq = state->response->data.sequence_number;
370 if (seq == DOM_SEQUENCE_NONE) {
371 state->extra_data = talloc_asprintf(state->mem_ctx,
372 "%s%s : DISCONNECTED\n",
374 state->domain->name);
376 state->extra_data = talloc_asprintf(state->mem_ctx,
379 state->domain->name, seq);
382 state->domain->sequence_number = seq;
384 state->domain = state->domain->next;
386 if (state->domain == NULL) {
387 struct winbindd_cli_state *cli_state = state->cli_state;
388 cli_state->response.length =
389 sizeof(cli_state->response) +
390 strlen(state->extra_data) + 1;
391 cli_state->response.extra_data.data =
392 SMB_STRDUP(state->extra_data);
393 request_ok(cli_state);
397 /* Ask the next domain */
398 fstrcpy(state->request->domain_name, state->domain->name);
399 async_domain_request(state->mem_ctx, state->domain,
400 state->request, state->response,
401 sequence_recv, state);
404 /* This is the child-only version of --sequence. It only allows for a single
405 * domain (ie "our" one) to be displayed. */
407 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
408 struct winbindd_cli_state *state)
410 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
412 /* Ensure null termination */
413 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
415 domain->methods->sequence_number(domain, &domain->sequence_number);
417 state->response.data.sequence_number =
418 domain->sequence_number;
423 struct domain_info_state {
424 struct winbindd_domain *domain;
425 struct winbindd_cli_state *cli_state;
428 static void domain_info_init_recv(void *private_data, BOOL success);
430 void winbindd_domain_info(struct winbindd_cli_state *state)
432 struct winbindd_domain *domain;
434 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
435 state->request.domain_name));
437 domain = find_domain_from_name_noinit(state->request.domain_name);
439 if (domain == NULL) {
440 DEBUG(3, ("Did not find domain [%s]\n",
441 state->request.domain_name));
442 request_error(state);
446 if (!domain->initialized) {
447 struct domain_info_state *istate;
449 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
450 if (istate == NULL) {
451 DEBUG(0, ("talloc failed\n"));
452 request_error(state);
456 istate->cli_state = state;
457 istate->domain = domain;
459 init_child_connection(domain, domain_info_init_recv, istate);
464 fstrcpy(state->response.data.domain_info.name,
466 fstrcpy(state->response.data.domain_info.alt_name,
468 fstrcpy(state->response.data.domain_info.sid,
469 sid_string_static(&domain->sid));
471 state->response.data.domain_info.native_mode =
473 state->response.data.domain_info.active_directory =
474 domain->active_directory;
475 state->response.data.domain_info.primary =
481 static void domain_info_init_recv(void *private_data, BOOL success)
483 struct domain_info_state *istate =
484 (struct domain_info_state *)private_data;
485 struct winbindd_cli_state *state = istate->cli_state;
486 struct winbindd_domain *domain = istate->domain;
488 DEBUG(10, ("Got back from child init: %d\n", success));
490 if ((!success) || (!domain->initialized)) {
491 DEBUG(5, ("Could not init child for domain %s\n",
493 request_error(state);
497 fstrcpy(state->response.data.domain_info.name,
499 fstrcpy(state->response.data.domain_info.alt_name,
501 fstrcpy(state->response.data.domain_info.sid,
502 sid_string_static(&domain->sid));
504 state->response.data.domain_info.native_mode =
506 state->response.data.domain_info.active_directory =
507 domain->active_directory;
508 state->response.data.domain_info.primary =
514 void winbindd_ping(struct winbindd_cli_state *state)
516 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
520 /* List various tidbits of information */
522 void winbindd_info(struct winbindd_cli_state *state)
525 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
527 state->response.data.info.winbind_separator = *lp_winbind_separator();
528 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
532 /* Tell the client the current interface version */
534 void winbindd_interface_version(struct winbindd_cli_state *state)
536 DEBUG(3, ("[%5lu]: request interface version\n",
537 (unsigned long)state->pid));
539 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
543 /* What domain are we a member of? */
545 void winbindd_domain_name(struct winbindd_cli_state *state)
547 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
549 fstrcpy(state->response.data.domain_name, lp_workgroup());
553 /* What's my name again? */
555 void winbindd_netbios_name(struct winbindd_cli_state *state)
557 DEBUG(3, ("[%5lu]: request netbios name\n",
558 (unsigned long)state->pid));
560 fstrcpy(state->response.data.netbios_name, global_myname());
564 /* Where can I find the privilaged pipe? */
566 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
569 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
570 (unsigned long)state->pid));
572 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
573 if (!state->response.extra_data.data) {
574 DEBUG(0, ("malloc failed\n"));
575 request_error(state);
579 /* must add one to length to copy the 0 for string termination */
580 state->response.length +=
581 strlen((char *)state->response.extra_data.data) + 1;