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 char *dcname_slash
= NULL
;
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 sid_to_fstring(state
->response
.data
.domain_info
.sid
, &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 sid_to_fstring(state
->response
.data
.domain_info
.sid
, &domain
->sid
);
503 state
->response
.data
.domain_info
.native_mode
=
505 state
->response
.data
.domain_info
.active_directory
=
506 domain
->active_directory
;
507 state
->response
.data
.domain_info
.primary
=
513 void winbindd_ping(struct winbindd_cli_state
*state
)
515 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state
->pid
));
519 /* List various tidbits of information */
521 void winbindd_info(struct winbindd_cli_state
*state
)
524 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state
->pid
));
526 state
->response
.data
.info
.winbind_separator
= *lp_winbind_separator();
527 fstrcpy(state
->response
.data
.info
.samba_version
, SAMBA_VERSION_STRING
);
531 /* Tell the client the current interface version */
533 void winbindd_interface_version(struct winbindd_cli_state
*state
)
535 DEBUG(3, ("[%5lu]: request interface version\n",
536 (unsigned long)state
->pid
));
538 state
->response
.data
.interface_version
= WINBIND_INTERFACE_VERSION
;
542 /* What domain are we a member of? */
544 void winbindd_domain_name(struct winbindd_cli_state
*state
)
546 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state
->pid
));
548 fstrcpy(state
->response
.data
.domain_name
, lp_workgroup());
552 /* What's my name again? */
554 void winbindd_netbios_name(struct winbindd_cli_state
*state
)
556 DEBUG(3, ("[%5lu]: request netbios name\n",
557 (unsigned long)state
->pid
));
559 fstrcpy(state
->response
.data
.netbios_name
, global_myname());
563 /* Where can I find the privilaged pipe? */
565 void winbindd_priv_pipe_dir(struct winbindd_cli_state
*state
)
568 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
569 (unsigned long)state
->pid
));
571 state
->response
.extra_data
.data
= SMB_STRDUP(get_winbind_priv_pipe_dir());
572 if (!state
->response
.extra_data
.data
) {
573 DEBUG(0, ("malloc failed\n"));
574 request_error(state
);
578 /* must add one to length to copy the 0 for string termination */
579 state
->response
.length
+=
580 strlen((char *)state
->response
.extra_data
.data
) + 1;