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 /* Constants and helper functions for determining domain trust types */
109 const char *trust_type_strings
[] = {"External",
114 static enum trust_type
get_trust_type(struct winbindd_tdc_domain
*domain
)
116 if (domain
->trust_attribs
== NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
)
118 else if (domain
->trust_attribs
== NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
)
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))
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
))
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
;
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
);
175 for ( i
= 0; i
< num_domains
; i
++ ) {
176 struct winbindd_domain
*domain
;
177 bool is_online
= true;
180 domain
= find_domain_from_name_noinit(d
->domain_name
);
182 is_online
= domain
->online
;
186 extra_data
= talloc_asprintf(state
->mem_ctx
,
187 "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
189 d
->dns_name
? d
->dns_name
: d
->domain_name
,
190 sid_string_talloc(state
->mem_ctx
, &d
->sid
),
191 get_trust_type_string(d
),
192 trust_is_transitive(d
) ? "Yes" : "No",
193 trust_is_inbound(d
) ? "Yes" : "No",
194 trust_is_outbound(d
) ? "Yes" : "No",
195 is_online
? "Online" : "Offline" );
197 extra_data
= talloc_asprintf(state
->mem_ctx
,
198 "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
201 d
->dns_name
? d
->dns_name
: d
->domain_name
,
202 sid_string_talloc(state
->mem_ctx
, &d
->sid
),
203 get_trust_type_string(d
),
204 trust_is_transitive(d
) ? "Yes" : "No",
205 trust_is_inbound(d
) ? "Yes" : "No",
206 trust_is_outbound(d
) ? "Yes" : "No",
207 is_online
? "Online" : "Offline" );
212 if (extra_data
!= NULL
) {
213 extra_data_len
= strlen(extra_data
);
216 if (extra_data_len
> 0) {
217 state
->response
.extra_data
.data
= SMB_STRDUP(extra_data
);
218 state
->response
.length
+= extra_data_len
+1;
223 TALLOC_FREE( dom_list
);
224 TALLOC_FREE( extra_data
);
227 enum winbindd_result
winbindd_dual_list_trusted_domains(struct winbindd_domain
*domain
,
228 struct winbindd_cli_state
*state
)
230 uint32 i
, num_domains
;
231 char **names
, **alt_names
;
233 int extra_data_len
= 0;
236 bool have_own_domain
= False
;
238 DEBUG(3, ("[%5lu]: list trusted domains\n",
239 (unsigned long)state
->pid
));
241 result
= domain
->methods
->trusted_domains(domain
, state
->mem_ctx
,
242 &num_domains
, &names
,
245 if (!NT_STATUS_IS_OK(result
)) {
246 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
247 nt_errstr(result
) ));
248 return WINBINDD_ERROR
;
251 extra_data
= talloc_strdup(state
->mem_ctx
, "");
254 extra_data
= talloc_asprintf(
255 state
->mem_ctx
, "%s\\%s\\%s",
256 names
[0], alt_names
[0] ? alt_names
[0] : names
[0],
257 sid_string_talloc(state
->mem_ctx
, &sids
[0]));
259 for (i
=1; i
<num_domains
; i
++)
260 extra_data
= talloc_asprintf(
261 state
->mem_ctx
, "%s\n%s\\%s\\%s",
262 extra_data
, names
[i
],
263 alt_names
[i
] ? alt_names
[i
] : names
[i
],
264 sid_string_talloc(state
->mem_ctx
, &sids
[i
]));
266 /* add our primary domain */
268 for (i
=0; i
<num_domains
; i
++) {
269 if (strequal(names
[i
], domain
->name
)) {
270 have_own_domain
= True
;
275 if (state
->request
.data
.list_all_domains
&& !have_own_domain
) {
276 extra_data
= talloc_asprintf(
277 state
->mem_ctx
, "%s\n%s\\%s\\%s",
278 extra_data
, domain
->name
,
279 domain
->alt_name
? domain
->alt_name
: domain
->name
,
280 sid_string_talloc(state
->mem_ctx
, &domain
->sid
));
283 /* This is a bit excessive, but the extra data sooner or later will be
287 if (extra_data
!= NULL
) {
288 extra_data_len
= strlen(extra_data
);
291 if (extra_data_len
> 0) {
292 state
->response
.extra_data
.data
= SMB_STRDUP(extra_data
);
293 state
->response
.length
+= extra_data_len
+1;
299 void winbindd_getdcname(struct winbindd_cli_state
*state
)
301 struct winbindd_domain
*domain
;
303 state
->request
.domain_name
304 [sizeof(state
->request
.domain_name
)-1] = '\0';
306 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state
->pid
,
307 state
->request
.domain_name
));
309 domain
= find_domain_from_name_noinit(state
->request
.domain_name
);
310 if (domain
&& domain
->internal
) {
311 fstrcpy(state
->response
.data
.dc_name
, global_myname());
316 sendto_domain(state
, find_our_domain());
319 enum winbindd_result
winbindd_dual_getdcname(struct winbindd_domain
*domain
,
320 struct winbindd_cli_state
*state
)
322 const char *dcname_slash
= NULL
;
324 struct rpc_pipe_client
*netlogon_pipe
;
327 unsigned int orig_timeout
;
328 struct winbindd_domain
*req_domain
;
330 state
->request
.domain_name
331 [sizeof(state
->request
.domain_name
)-1] = '\0';
333 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state
->pid
,
334 state
->request
.domain_name
));
336 result
= cm_connect_netlogon(domain
, &netlogon_pipe
);
338 if (!NT_STATUS_IS_OK(result
)) {
339 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
340 return WINBINDD_ERROR
;
343 /* This call can take a long time - allow the server to time out.
344 35 seconds should do it. */
346 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
348 req_domain
= find_domain_from_name_noinit(state
->request
.domain_name
);
349 if (req_domain
== domain
) {
350 result
= rpccli_netr_GetDcName(netlogon_pipe
,
353 state
->request
.domain_name
,
357 result
= rpccli_netr_GetAnyDCName(netlogon_pipe
,
360 state
->request
.domain_name
,
364 /* And restore our original timeout. */
365 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
367 if (!NT_STATUS_IS_OK(result
)) {
368 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
369 state
->request
.domain_name
, nt_errstr(result
)));
370 return WINBINDD_ERROR
;
373 if (!W_ERROR_IS_OK(werr
)) {
374 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
375 state
->request
.domain_name
, dos_errstr(werr
)));
376 return WINBINDD_ERROR
;
387 fstrcpy(state
->response
.data
.dc_name
, p
);
391 struct sequence_state
{
393 struct winbindd_cli_state
*cli_state
;
394 struct winbindd_domain
*domain
;
395 struct winbindd_request
*request
;
396 struct winbindd_response
*response
;
400 static void sequence_recv(void *private_data
, bool success
);
402 void winbindd_show_sequence(struct winbindd_cli_state
*state
)
404 struct sequence_state
*seq
;
406 /* Ensure null termination */
407 state
->request
.domain_name
[sizeof(state
->request
.domain_name
)-1]='\0';
409 if (strlen(state
->request
.domain_name
) > 0) {
410 struct winbindd_domain
*domain
;
411 domain
= find_domain_from_name_noinit(
412 state
->request
.domain_name
);
413 if (domain
== NULL
) {
414 request_error(state
);
417 sendto_domain(state
, domain
);
421 /* Ask all domains in sequence, collect the results in sequence_recv */
423 seq
= TALLOC_P(state
->mem_ctx
, struct sequence_state
);
425 DEBUG(0, ("talloc failed\n"));
426 request_error(state
);
430 seq
->mem_ctx
= state
->mem_ctx
;
431 seq
->cli_state
= state
;
432 seq
->domain
= domain_list();
433 if (seq
->domain
== NULL
) {
434 DEBUG(0, ("domain list empty\n"));
435 request_error(state
);
438 seq
->request
= TALLOC_ZERO_P(state
->mem_ctx
,
439 struct winbindd_request
);
440 seq
->response
= TALLOC_ZERO_P(state
->mem_ctx
,
441 struct winbindd_response
);
442 seq
->extra_data
= talloc_strdup(state
->mem_ctx
, "");
444 if ((seq
->request
== NULL
) || (seq
->response
== NULL
) ||
445 (seq
->extra_data
== NULL
)) {
446 DEBUG(0, ("talloc failed\n"));
447 request_error(state
);
451 seq
->request
->length
= sizeof(*seq
->request
);
452 seq
->request
->cmd
= WINBINDD_SHOW_SEQUENCE
;
453 fstrcpy(seq
->request
->domain_name
, seq
->domain
->name
);
455 async_domain_request(state
->mem_ctx
, seq
->domain
,
456 seq
->request
, seq
->response
,
460 static void sequence_recv(void *private_data
, bool success
)
462 struct sequence_state
*state
=
463 (struct sequence_state
*)private_data
;
464 uint32 seq
= DOM_SEQUENCE_NONE
;
466 if ((success
) && (state
->response
->result
== WINBINDD_OK
))
467 seq
= state
->response
->data
.sequence_number
;
469 if (seq
== DOM_SEQUENCE_NONE
) {
470 state
->extra_data
= talloc_asprintf(state
->mem_ctx
,
471 "%s%s : DISCONNECTED\n",
473 state
->domain
->name
);
475 state
->extra_data
= talloc_asprintf(state
->mem_ctx
,
478 state
->domain
->name
, seq
);
481 state
->domain
->sequence_number
= seq
;
483 state
->domain
= state
->domain
->next
;
485 if (state
->domain
== NULL
) {
486 struct winbindd_cli_state
*cli_state
= state
->cli_state
;
487 cli_state
->response
.length
=
488 sizeof(cli_state
->response
) +
489 strlen(state
->extra_data
) + 1;
490 cli_state
->response
.extra_data
.data
=
491 SMB_STRDUP(state
->extra_data
);
492 request_ok(cli_state
);
496 /* Ask the next domain */
497 fstrcpy(state
->request
->domain_name
, state
->domain
->name
);
498 async_domain_request(state
->mem_ctx
, state
->domain
,
499 state
->request
, state
->response
,
500 sequence_recv
, state
);
503 /* This is the child-only version of --sequence. It only allows for a single
504 * domain (ie "our" one) to be displayed. */
506 enum winbindd_result
winbindd_dual_show_sequence(struct winbindd_domain
*domain
,
507 struct winbindd_cli_state
*state
)
509 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state
->pid
));
511 /* Ensure null termination */
512 state
->request
.domain_name
[sizeof(state
->request
.domain_name
)-1]='\0';
514 domain
->methods
->sequence_number(domain
, &domain
->sequence_number
);
516 state
->response
.data
.sequence_number
=
517 domain
->sequence_number
;
522 struct domain_info_state
{
523 struct winbindd_domain
*domain
;
524 struct winbindd_cli_state
*cli_state
;
527 static void domain_info_init_recv(void *private_data
, bool success
);
529 void winbindd_domain_info(struct winbindd_cli_state
*state
)
531 struct winbindd_domain
*domain
;
533 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state
->pid
,
534 state
->request
.domain_name
));
536 domain
= find_domain_from_name_noinit(state
->request
.domain_name
);
538 if (domain
== NULL
) {
539 DEBUG(3, ("Did not find domain [%s]\n",
540 state
->request
.domain_name
));
541 request_error(state
);
545 if (!domain
->initialized
) {
546 struct domain_info_state
*istate
;
548 istate
= TALLOC_P(state
->mem_ctx
, struct domain_info_state
);
549 if (istate
== NULL
) {
550 DEBUG(0, ("talloc failed\n"));
551 request_error(state
);
555 istate
->cli_state
= state
;
556 istate
->domain
= domain
;
558 init_child_connection(domain
, domain_info_init_recv
, istate
);
563 fstrcpy(state
->response
.data
.domain_info
.name
,
565 fstrcpy(state
->response
.data
.domain_info
.alt_name
,
567 sid_to_fstring(state
->response
.data
.domain_info
.sid
, &domain
->sid
);
569 state
->response
.data
.domain_info
.native_mode
=
571 state
->response
.data
.domain_info
.active_directory
=
572 domain
->active_directory
;
573 state
->response
.data
.domain_info
.primary
=
579 static void domain_info_init_recv(void *private_data
, bool success
)
581 struct domain_info_state
*istate
=
582 (struct domain_info_state
*)private_data
;
583 struct winbindd_cli_state
*state
= istate
->cli_state
;
584 struct winbindd_domain
*domain
= istate
->domain
;
586 DEBUG(10, ("Got back from child init: %d\n", success
));
588 if ((!success
) || (!domain
->initialized
)) {
589 DEBUG(5, ("Could not init child for domain %s\n",
591 request_error(state
);
595 fstrcpy(state
->response
.data
.domain_info
.name
,
597 fstrcpy(state
->response
.data
.domain_info
.alt_name
,
599 sid_to_fstring(state
->response
.data
.domain_info
.sid
, &domain
->sid
);
601 state
->response
.data
.domain_info
.native_mode
=
603 state
->response
.data
.domain_info
.active_directory
=
604 domain
->active_directory
;
605 state
->response
.data
.domain_info
.primary
=
611 void winbindd_ping(struct winbindd_cli_state
*state
)
613 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state
->pid
));
617 /* List various tidbits of information */
619 void winbindd_info(struct winbindd_cli_state
*state
)
622 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state
->pid
));
624 state
->response
.data
.info
.winbind_separator
= *lp_winbind_separator();
625 fstrcpy(state
->response
.data
.info
.samba_version
, SAMBA_VERSION_STRING
);
629 /* Tell the client the current interface version */
631 void winbindd_interface_version(struct winbindd_cli_state
*state
)
633 DEBUG(3, ("[%5lu]: request interface version\n",
634 (unsigned long)state
->pid
));
636 state
->response
.data
.interface_version
= WINBIND_INTERFACE_VERSION
;
640 /* What domain are we a member of? */
642 void winbindd_domain_name(struct winbindd_cli_state
*state
)
644 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state
->pid
));
646 fstrcpy(state
->response
.data
.domain_name
, lp_workgroup());
650 /* What's my name again? */
652 void winbindd_netbios_name(struct winbindd_cli_state
*state
)
654 DEBUG(3, ("[%5lu]: request netbios name\n",
655 (unsigned long)state
->pid
));
657 fstrcpy(state
->response
.data
.netbios_name
, global_myname());
661 /* Where can I find the privilaged pipe? */
663 void winbindd_priv_pipe_dir(struct winbindd_cli_state
*state
)
666 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
667 (unsigned long)state
->pid
));
669 state
->response
.extra_data
.data
= SMB_STRDUP(get_winbind_priv_pipe_dir());
670 if (!state
->response
.extra_data
.data
) {
671 DEBUG(0, ("malloc failed\n"));
672 request_error(state
);
676 /* must add one to length to copy the 0 for string termination */
677 state
->response
.length
+=
678 strlen((char *)state
->response
.extra_data
.data
) + 1;