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(
112 state->mem_ctx, "%s\\%s\\%s",
113 d->name, d->alt_name ? d->alt_name : d->name,
114 sid_string_talloc(state->mem_ctx, &d->sid));
116 extra_data = talloc_asprintf(
117 state->mem_ctx, "%s\n%s\\%s\\%s",
119 d->alt_name ? d->alt_name : d->name,
120 sid_string_talloc(state->mem_ctx, &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(
167 state->mem_ctx, "%s\\%s\\%s",
168 names[0], alt_names[0] ? alt_names[0] : names[0],
169 sid_string_talloc(state->mem_ctx, &sids[0]));
171 for (i=1; i<num_domains; i++)
172 extra_data = talloc_asprintf(
173 state->mem_ctx, "%s\n%s\\%s\\%s",
174 extra_data, names[i],
175 alt_names[i] ? alt_names[i] : names[i],
176 sid_string_talloc(state->mem_ctx, &sids[i]));
178 /* add our primary domain */
180 for (i=0; i<num_domains; i++) {
181 if (strequal(names[i], domain->name)) {
182 have_own_domain = True;
187 if (state->request.data.list_all_domains && !have_own_domain) {
188 extra_data = talloc_asprintf(
189 state->mem_ctx, "%s\n%s\\%s\\%s",
190 extra_data, domain->name,
191 domain->alt_name ? domain->alt_name : domain->name,
192 sid_string_talloc(state->mem_ctx, &domain->sid));
195 /* This is a bit excessive, but the extra data sooner or later will be
199 if (extra_data != NULL) {
200 extra_data_len = strlen(extra_data);
203 if (extra_data_len > 0) {
204 state->response.extra_data.data = SMB_STRDUP(extra_data);
205 state->response.length += extra_data_len+1;
211 void winbindd_getdcname(struct winbindd_cli_state *state)
213 struct winbindd_domain *domain;
215 state->request.domain_name
216 [sizeof(state->request.domain_name)-1] = '\0';
218 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
219 state->request.domain_name));
221 domain = find_domain_from_name_noinit(state->request.domain_name);
222 if (domain && domain->internal) {
223 fstrcpy(state->response.data.dc_name, global_myname());
228 sendto_domain(state, find_our_domain());
231 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
232 struct winbindd_cli_state *state)
234 fstring dcname_slash;
236 struct rpc_pipe_client *netlogon_pipe;
239 unsigned int orig_timeout;
240 struct winbindd_domain *req_domain;
242 state->request.domain_name
243 [sizeof(state->request.domain_name)-1] = '\0';
245 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
246 state->request.domain_name));
248 result = cm_connect_netlogon(domain, &netlogon_pipe);
250 if (!NT_STATUS_IS_OK(result)) {
251 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
252 return WINBINDD_ERROR;
255 /* This call can take a long time - allow the server to time out.
256 35 seconds should do it. */
258 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
260 req_domain = find_domain_from_name_noinit(state->request.domain_name);
261 if (req_domain == domain) {
262 werr = rpccli_netlogon_getdcname(netlogon_pipe, state->mem_ctx,
264 state->request.domain_name,
267 werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx,
269 state->request.domain_name,
272 /* And restore our original timeout. */
273 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
275 if (!W_ERROR_IS_OK(werr)) {
276 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
277 state->request.domain_name, dos_errstr(werr)));
278 return WINBINDD_ERROR;
289 fstrcpy(state->response.data.dc_name, p);
293 struct sequence_state {
295 struct winbindd_cli_state *cli_state;
296 struct winbindd_domain *domain;
297 struct winbindd_request *request;
298 struct winbindd_response *response;
302 static void sequence_recv(void *private_data, bool success);
304 void winbindd_show_sequence(struct winbindd_cli_state *state)
306 struct sequence_state *seq;
308 /* Ensure null termination */
309 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
311 if (strlen(state->request.domain_name) > 0) {
312 struct winbindd_domain *domain;
313 domain = find_domain_from_name_noinit(
314 state->request.domain_name);
315 if (domain == NULL) {
316 request_error(state);
319 sendto_domain(state, domain);
323 /* Ask all domains in sequence, collect the results in sequence_recv */
325 seq = TALLOC_P(state->mem_ctx, struct sequence_state);
327 DEBUG(0, ("talloc failed\n"));
328 request_error(state);
332 seq->mem_ctx = state->mem_ctx;
333 seq->cli_state = state;
334 seq->domain = domain_list();
335 if (seq->domain == NULL) {
336 DEBUG(0, ("domain list empty\n"));
337 request_error(state);
340 seq->request = TALLOC_ZERO_P(state->mem_ctx,
341 struct winbindd_request);
342 seq->response = TALLOC_ZERO_P(state->mem_ctx,
343 struct winbindd_response);
344 seq->extra_data = talloc_strdup(state->mem_ctx, "");
346 if ((seq->request == NULL) || (seq->response == NULL) ||
347 (seq->extra_data == NULL)) {
348 DEBUG(0, ("talloc failed\n"));
349 request_error(state);
353 seq->request->length = sizeof(*seq->request);
354 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
355 fstrcpy(seq->request->domain_name, seq->domain->name);
357 async_domain_request(state->mem_ctx, seq->domain,
358 seq->request, seq->response,
362 static void sequence_recv(void *private_data, bool success)
364 struct sequence_state *state =
365 (struct sequence_state *)private_data;
366 uint32 seq = DOM_SEQUENCE_NONE;
368 if ((success) && (state->response->result == WINBINDD_OK))
369 seq = state->response->data.sequence_number;
371 if (seq == DOM_SEQUENCE_NONE) {
372 state->extra_data = talloc_asprintf(state->mem_ctx,
373 "%s%s : DISCONNECTED\n",
375 state->domain->name);
377 state->extra_data = talloc_asprintf(state->mem_ctx,
380 state->domain->name, seq);
383 state->domain->sequence_number = seq;
385 state->domain = state->domain->next;
387 if (state->domain == NULL) {
388 struct winbindd_cli_state *cli_state = state->cli_state;
389 cli_state->response.length =
390 sizeof(cli_state->response) +
391 strlen(state->extra_data) + 1;
392 cli_state->response.extra_data.data =
393 SMB_STRDUP(state->extra_data);
394 request_ok(cli_state);
398 /* Ask the next domain */
399 fstrcpy(state->request->domain_name, state->domain->name);
400 async_domain_request(state->mem_ctx, state->domain,
401 state->request, state->response,
402 sequence_recv, state);
405 /* This is the child-only version of --sequence. It only allows for a single
406 * domain (ie "our" one) to be displayed. */
408 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
409 struct winbindd_cli_state *state)
411 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
413 /* Ensure null termination */
414 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
416 domain->methods->sequence_number(domain, &domain->sequence_number);
418 state->response.data.sequence_number =
419 domain->sequence_number;
424 struct domain_info_state {
425 struct winbindd_domain *domain;
426 struct winbindd_cli_state *cli_state;
429 static void domain_info_init_recv(void *private_data, bool success);
431 void winbindd_domain_info(struct winbindd_cli_state *state)
433 struct winbindd_domain *domain;
435 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
436 state->request.domain_name));
438 domain = find_domain_from_name_noinit(state->request.domain_name);
440 if (domain == NULL) {
441 DEBUG(3, ("Did not find domain [%s]\n",
442 state->request.domain_name));
443 request_error(state);
447 if (!domain->initialized) {
448 struct domain_info_state *istate;
450 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
451 if (istate == NULL) {
452 DEBUG(0, ("talloc failed\n"));
453 request_error(state);
457 istate->cli_state = state;
458 istate->domain = domain;
460 init_child_connection(domain, domain_info_init_recv, istate);
465 fstrcpy(state->response.data.domain_info.name,
467 fstrcpy(state->response.data.domain_info.alt_name,
469 fstrcpy(state->response.data.domain_info.sid,
470 sid_string_static(&domain->sid));
472 state->response.data.domain_info.native_mode =
474 state->response.data.domain_info.active_directory =
475 domain->active_directory;
476 state->response.data.domain_info.primary =
482 static void domain_info_init_recv(void *private_data, bool success)
484 struct domain_info_state *istate =
485 (struct domain_info_state *)private_data;
486 struct winbindd_cli_state *state = istate->cli_state;
487 struct winbindd_domain *domain = istate->domain;
489 DEBUG(10, ("Got back from child init: %d\n", success));
491 if ((!success) || (!domain->initialized)) {
492 DEBUG(5, ("Could not init child for domain %s\n",
494 request_error(state);
498 fstrcpy(state->response.data.domain_info.name,
500 fstrcpy(state->response.data.domain_info.alt_name,
502 fstrcpy(state->response.data.domain_info.sid,
503 sid_string_static(&domain->sid));
505 state->response.data.domain_info.native_mode =
507 state->response.data.domain_info.active_directory =
508 domain->active_directory;
509 state->response.data.domain_info.primary =
515 void winbindd_ping(struct winbindd_cli_state *state)
517 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
521 /* List various tidbits of information */
523 void winbindd_info(struct winbindd_cli_state *state)
526 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
528 state->response.data.info.winbind_separator = *lp_winbind_separator();
529 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
533 /* Tell the client the current interface version */
535 void winbindd_interface_version(struct winbindd_cli_state *state)
537 DEBUG(3, ("[%5lu]: request interface version\n",
538 (unsigned long)state->pid));
540 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
544 /* What domain are we a member of? */
546 void winbindd_domain_name(struct winbindd_cli_state *state)
548 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
550 fstrcpy(state->response.data.domain_name, lp_workgroup());
554 /* What's my name again? */
556 void winbindd_netbios_name(struct winbindd_cli_state *state)
558 DEBUG(3, ("[%5lu]: request netbios name\n",
559 (unsigned long)state->pid));
561 fstrcpy(state->response.data.netbios_name, global_myname());
565 /* Where can I find the privilaged pipe? */
567 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
570 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
571 (unsigned long)state->pid));
573 state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
574 if (!state->response.extra_data.data) {
575 DEBUG(0, ("malloc failed\n"));
576 request_error(state);
580 /* must add one to length to copy the 0 for string termination */
581 state->response.length +=
582 strlen((char *)state->response.extra_data.data) + 1;