2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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/>.
25 #include "lib/util_unixsids.h"
27 #include "../libcli/security/security.h"
28 #include "../libcli/auth/pam_errors.h"
29 #include "passdb/machine_sid.h"
31 #include "source4/lib/messaging/messaging.h"
32 #include "librpc/gen_ndr/ndr_lsa.h"
33 #include "auth/credentials/credentials.h"
34 #include "libsmb/samlogon_cache.h"
37 #define DBGC_CLASS DBGC_WINBIND
39 static struct winbindd_domain
*
40 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain
*tdc
);
43 * @file winbindd_util.c
45 * Winbind daemon for NT domain authentication nss module.
49 /* The list of trusted domains. Note that the list can be deleted and
50 recreated using the init_domain_list() function so pointers to
51 individual winbindd_domain structures cannot be made. Keep a copy of
52 the domain name instead. */
54 static struct winbindd_domain
*_domain_list
= NULL
;
56 struct winbindd_domain
*domain_list(void)
60 if ((!_domain_list
) && (!init_domain_list())) {
61 smb_panic("Init_domain_list failed");
67 /* Free all entries in the trusted domain list */
69 static void free_domain_list(void)
71 struct winbindd_domain
*domain
= _domain_list
;
74 struct winbindd_domain
*next
= domain
->next
;
76 DLIST_REMOVE(_domain_list
, domain
);
83 * Iterator for winbindd's domain list.
84 * To be used (e.g.) in tevent based loops.
86 struct winbindd_domain
*wb_next_domain(struct winbindd_domain
*domain
)
89 domain
= domain_list();
91 domain
= domain
->next
;
94 if ((domain
!= NULL
) &&
95 (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC
) &&
96 sid_check_is_our_sam(&domain
->sid
))
98 domain
= domain
->next
;
104 static bool is_internal_domain(const struct dom_sid
*sid
)
109 return (sid_check_is_our_sam(sid
) || sid_check_is_builtin(sid
));
112 static bool is_in_internal_domain(const struct dom_sid
*sid
)
117 return (sid_check_is_in_our_sam(sid
) || sid_check_is_in_builtin(sid
));
121 /* Add a trusted domain to our list of domains.
122 If the domain already exists in the list,
123 return it and don't re-initialize. */
125 static struct winbindd_domain
*
126 add_trusted_domain(const char *domain_name
, const char *alt_name
,
127 const struct dom_sid
*sid
)
129 struct winbindd_tdc_domain tdc
;
133 tdc
.domain_name
= domain_name
;
134 tdc
.dns_name
= alt_name
;
136 sid_copy(&tdc
.sid
, sid
);
139 return add_trusted_domain_from_tdc(&tdc
);
142 /* Add a trusted domain out of a trusted domain cache
145 static struct winbindd_domain
*
146 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain
*tdc
)
148 struct winbindd_domain
*domain
;
149 const char *alternative_name
= NULL
;
150 const char **ignored_domains
, **dom
;
151 int role
= lp_server_role();
152 const char *domain_name
= tdc
->domain_name
;
153 const struct dom_sid
*sid
= &tdc
->sid
;
155 if (is_null_sid(sid
)) {
159 ignored_domains
= lp_parm_string_list(-1, "winbind", "ignore domains", NULL
);
160 for (dom
=ignored_domains
; dom
&& *dom
; dom
++) {
161 if (gen_fnmatch(*dom
, domain_name
) == 0) {
162 DEBUG(2,("Ignoring domain '%s'\n", domain_name
));
167 /* use alt_name if available to allow DNS lookups */
169 if (tdc
->dns_name
&& *tdc
->dns_name
) {
170 alternative_name
= tdc
->dns_name
;
173 /* We can't call domain_list() as this function is called from
174 init_domain_list() and we'll get stuck in a loop. */
175 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
176 if (strequal(domain_name
, domain
->name
) ||
177 strequal(domain_name
, domain
->alt_name
))
182 if (alternative_name
) {
183 if (strequal(alternative_name
, domain
->name
) ||
184 strequal(alternative_name
, domain
->alt_name
))
191 if (dom_sid_equal(sid
, &domain
->sid
)) {
197 if (domain
!= NULL
) {
199 * We found a match on domain->name or
200 * domain->alt_name. Possibly update the SID
201 * if the stored SID was the NULL SID
202 * and return the matching entry.
205 && dom_sid_equal(&domain
->sid
, &global_sid_NULL
)) {
206 sid_copy( &domain
->sid
, sid
);
211 /* Create new domain entry */
212 domain
= talloc_zero(NULL
, struct winbindd_domain
);
213 if (domain
== NULL
) {
217 domain
->children
= talloc_zero_array(domain
,
218 struct winbindd_child
,
219 lp_winbind_max_domain_connections());
220 if (domain
->children
== NULL
) {
225 domain
->name
= talloc_strdup(domain
, domain_name
);
226 if (domain
->name
== NULL
) {
231 if (alternative_name
) {
232 domain
->alt_name
= talloc_strdup(domain
, alternative_name
);
233 if (domain
->alt_name
== NULL
) {
239 domain
->backend
= NULL
;
240 domain
->internal
= is_internal_domain(sid
);
241 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
242 domain
->last_seq_check
= 0;
243 domain
->initialized
= false;
244 domain
->online
= is_internal_domain(sid
);
245 domain
->check_online_timeout
= 0;
246 domain
->dc_probe_pid
= (pid_t
)-1;
248 sid_copy(&domain
->sid
, sid
);
250 domain
->domain_flags
= tdc
->trust_flags
;
251 domain
->domain_type
= tdc
->trust_type
;
252 domain
->domain_trust_attribs
= tdc
->trust_attribs
;
254 /* Is this our primary domain ? */
255 if (role
== ROLE_DOMAIN_MEMBER
) {
256 domain
->primary
= strequal(domain_name
, lp_workgroup());
258 domain
->primary
= strequal(domain_name
, get_global_sam_name());
261 if (domain
->primary
) {
262 if (role
== ROLE_ACTIVE_DIRECTORY_DC
) {
263 domain
->active_directory
= true;
265 if (lp_security() == SEC_ADS
) {
266 domain
->active_directory
= true;
268 } else if (!domain
->internal
) {
269 if (domain
->domain_type
== LSA_TRUST_TYPE_UPLEVEL
) {
270 domain
->active_directory
= true;
274 /* Link to domain list */
275 DLIST_ADD_END(_domain_list
, domain
);
277 wcache_tdc_add_domain( domain
);
279 setup_domain_child(domain
);
282 ("Added domain %s %s %s\n", domain
->name
, domain
->alt_name
,
283 !is_null_sid(&domain
->sid
) ? sid_string_dbg(&domain
->sid
) : ""));
288 bool domain_is_forest_root(const struct winbindd_domain
*domain
)
290 const uint32_t fr_flags
=
291 (NETR_TRUST_FLAG_TREEROOT
|NETR_TRUST_FLAG_IN_FOREST
);
293 return ((domain
->domain_flags
& fr_flags
) == fr_flags
);
296 /********************************************************************
297 rescan our domains looking for new trusted domains
298 ********************************************************************/
300 struct trustdom_state
{
301 struct winbindd_domain
*domain
;
302 struct winbindd_request request
;
305 static void trustdom_list_done(struct tevent_req
*req
);
306 static void rescan_forest_root_trusts( void );
307 static void rescan_forest_trusts( void );
309 static void add_trusted_domains( struct winbindd_domain
*domain
)
311 struct trustdom_state
*state
;
312 struct tevent_req
*req
;
314 state
= talloc_zero(NULL
, struct trustdom_state
);
316 DEBUG(0, ("talloc failed\n"));
319 state
->domain
= domain
;
321 state
->request
.length
= sizeof(state
->request
);
322 state
->request
.cmd
= WINBINDD_LIST_TRUSTDOM
;
324 req
= wb_domain_request_send(state
, server_event_context(),
325 domain
, &state
->request
);
327 DEBUG(1, ("wb_domain_request_send failed\n"));
331 tevent_req_set_callback(req
, trustdom_list_done
, state
);
334 static void trustdom_list_done(struct tevent_req
*req
)
336 struct trustdom_state
*state
= tevent_req_callback_data(
337 req
, struct trustdom_state
);
338 struct winbindd_response
*response
;
341 struct winbindd_tdc_domain trust_params
= {0};
343 bool within_forest
= false;
346 * Only when we enumerate our primary domain
347 * or our forest root domain, we should keep
348 * the NETR_TRUST_FLAG_IN_FOREST flag, in
349 * all other cases we need to clear it as the domain
350 * is not part of our forest.
352 if (state
->domain
->primary
) {
353 within_forest
= true;
354 } else if (domain_is_forest_root(state
->domain
)) {
355 within_forest
= true;
358 res
= wb_domain_request_recv(req
, state
, &response
, &err
);
359 if ((res
== -1) || (response
->result
!= WINBINDD_OK
)) {
360 DBG_WARNING("Could not receive trusts for domain %s\n",
361 state
->domain
->name
);
366 if (response
->length
< sizeof(struct winbindd_response
)) {
367 DBG_ERR("ill-formed trustdom response - short length\n");
372 extra_len
= response
->length
- sizeof(struct winbindd_response
);
374 p
= (char *)response
->extra_data
.data
;
376 while ((p
- (char *)response
->extra_data
.data
) < extra_len
) {
377 char *q
, *sidstr
, *alt_name
;
379 DBG_DEBUG("parsing response line '%s'\n", p
);
381 ZERO_STRUCT(trust_params
);
382 trust_params
.domain_name
= p
;
384 alt_name
= strchr(p
, '\\');
385 if (alt_name
== NULL
) {
386 DBG_ERR("Got invalid trustdom response\n");
393 sidstr
= strchr(alt_name
, '\\');
394 if (sidstr
== NULL
) {
395 DBG_ERR("Got invalid trustdom response\n");
402 /* use the real alt_name if we have one, else pass in NULL */
403 if (!strequal(alt_name
, "(null)")) {
404 trust_params
.dns_name
= alt_name
;
407 q
= strtok(sidstr
, "\\");
409 DBG_ERR("Got invalid trustdom response\n");
413 if (!string_to_sid(&trust_params
.sid
, sidstr
)) {
414 DEBUG(0, ("Got invalid trustdom response\n"));
418 q
= strtok(NULL
, "\\");
420 DBG_ERR("Got invalid trustdom response\n");
424 trust_params
.trust_flags
= (uint32_t)strtoul(q
, NULL
, 10);
426 q
= strtok(NULL
, "\\");
428 DBG_ERR("Got invalid trustdom response\n");
432 trust_params
.trust_type
= (uint32_t)strtoul(q
, NULL
, 10);
434 q
= strtok(NULL
, "\n");
436 DBG_ERR("Got invalid trustdom response\n");
440 trust_params
.trust_attribs
= (uint32_t)strtoul(q
, NULL
, 10);
442 if (!within_forest
) {
443 trust_params
.trust_flags
&= ~NETR_TRUST_FLAG_IN_FOREST
;
446 if (!state
->domain
->primary
) {
447 trust_params
.trust_flags
&= ~NETR_TRUST_FLAG_PRIMARY
;
451 * We always call add_trusted_domain() cause on an existing
452 * domain structure, it will update the SID if necessary.
453 * This is important because we need the SID for sibling
456 (void)add_trusted_domain_from_tdc(&trust_params
);
458 p
= q
+ strlen(q
) + 1;
462 Cases to consider when scanning trusts:
463 (a) we are calling from a child domain (primary && !forest_root)
464 (b) we are calling from the root of the forest (primary && forest_root)
465 (c) we are calling from a trusted forest domain (!primary
469 if (state
->domain
->primary
) {
470 /* If this is our primary domain and we are not in the
471 forest root, we have to scan the root trusts first */
473 if (!domain_is_forest_root(state
->domain
))
474 rescan_forest_root_trusts();
476 rescan_forest_trusts();
478 } else if (domain_is_forest_root(state
->domain
)) {
479 /* Once we have done root forest trust search, we can
480 go on to search the trusted forests */
482 rescan_forest_trusts();
490 /********************************************************************
491 Scan the trusts of our forest root
492 ********************************************************************/
494 static void rescan_forest_root_trusts( void )
496 struct winbindd_tdc_domain
*dom_list
= NULL
;
497 size_t num_trusts
= 0;
500 /* The only transitive trusts supported by Windows 2003 AD are
501 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
502 first two are handled in forest and listed by
503 DsEnumerateDomainTrusts(). Forest trusts are not so we
504 have to do that ourselves. */
506 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
509 for ( i
=0; i
<num_trusts
; i
++ ) {
510 struct winbindd_domain
*d
= NULL
;
512 /* Find the forest root. Don't necessarily trust
513 the domain_list() as our primary domain may not
514 have been initialized. */
516 if ( !(dom_list
[i
].trust_flags
& NETR_TRUST_FLAG_TREEROOT
) ) {
520 /* Here's the forest root */
522 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
525 d
= add_trusted_domain_from_tdc(&dom_list
[i
]);
532 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
533 "for domain tree root %s (%s)\n",
534 d
->name
, d
->alt_name
));
536 d
->domain_flags
= dom_list
[i
].trust_flags
;
537 d
->domain_type
= dom_list
[i
].trust_type
;
538 d
->domain_trust_attribs
= dom_list
[i
].trust_attribs
;
540 add_trusted_domains( d
);
545 TALLOC_FREE( dom_list
);
550 /********************************************************************
551 scan the transitive forest trusts (not our own)
552 ********************************************************************/
555 static void rescan_forest_trusts( void )
557 struct winbindd_domain
*d
= NULL
;
558 struct winbindd_tdc_domain
*dom_list
= NULL
;
559 size_t num_trusts
= 0;
562 /* The only transitive trusts supported by Windows 2003 AD are
563 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
564 first two are handled in forest and listed by
565 DsEnumerateDomainTrusts(). Forest trusts are not so we
566 have to do that ourselves. */
568 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
571 for ( i
=0; i
<num_trusts
; i
++ ) {
572 uint32_t flags
= dom_list
[i
].trust_flags
;
573 uint32_t type
= dom_list
[i
].trust_type
;
574 uint32_t attribs
= dom_list
[i
].trust_attribs
;
576 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
578 /* ignore our primary and internal domains */
580 if ( d
&& (d
->internal
|| d
->primary
) )
583 if ( (flags
& NETR_TRUST_FLAG_INBOUND
) &&
584 (type
== LSA_TRUST_TYPE_UPLEVEL
) &&
585 (attribs
== LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) )
587 /* add the trusted domain if we don't know
591 d
= add_trusted_domain_from_tdc(&dom_list
[i
]);
598 DEBUG(10,("Following trust path for domain %s (%s)\n",
599 d
->name
, d
->alt_name
));
600 add_trusted_domains( d
);
604 TALLOC_FREE( dom_list
);
609 /*********************************************************************
610 The process of updating the trusted domain list is a three step
613 (b) ask the root domain in our forest
614 (c) ask the a DC in any Win2003 trusted forests
615 *********************************************************************/
617 void rescan_trusted_domains(struct tevent_context
*ev
, struct tevent_timer
*te
,
618 struct timeval now
, void *private_data
)
622 /* I use to clear the cache here and start over but that
623 caused problems in child processes that needed the
624 trust dom list early on. Removing it means we
625 could have some trusted domains listed that have been
626 removed from our primary domain's DC until a full
627 restart. This should be ok since I think this is what
628 Windows does as well. */
630 /* this will only add new domains we didn't already know about
631 in the domain_list()*/
633 add_trusted_domains( find_our_domain() );
635 te
= tevent_add_timer(
636 ev
, NULL
, timeval_current_ofs(WINBINDD_RESCAN_FREQ
, 0),
637 rescan_trusted_domains
, NULL
);
639 * If te == NULL, there's not much we can do here. Don't fail, the
640 * only thing we miss is new trusted domains.
646 enum winbindd_result
winbindd_dual_init_connection(struct winbindd_domain
*domain
,
647 struct winbindd_cli_state
*state
)
649 /* Ensure null termination */
650 state
->request
->domain_name
651 [sizeof(state
->request
->domain_name
)-1]='\0';
652 state
->request
->data
.init_conn
.dcname
653 [sizeof(state
->request
->data
.init_conn
.dcname
)-1]='\0';
655 if (strlen(state
->request
->data
.init_conn
.dcname
) > 0) {
656 fstrcpy(domain
->dcname
, state
->request
->data
.init_conn
.dcname
);
659 init_dc_connection(domain
, false);
661 if (!domain
->initialized
) {
662 /* If we return error here we can't do any cached authentication,
663 but we may be in disconnected mode and can't initialize correctly.
664 Do what the previous code did and just return without initialization,
665 once we go online we'll re-initialize.
667 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
668 "online = %d\n", domain
->name
, (int)domain
->online
));
671 fstrcpy(state
->response
->data
.domain_info
.name
, domain
->name
);
672 fstrcpy(state
->response
->data
.domain_info
.alt_name
, domain
->alt_name
);
673 sid_to_fstring(state
->response
->data
.domain_info
.sid
, &domain
->sid
);
675 state
->response
->data
.domain_info
.native_mode
676 = domain
->native_mode
;
677 state
->response
->data
.domain_info
.active_directory
678 = domain
->active_directory
;
679 state
->response
->data
.domain_info
.primary
685 static void wb_imsg_new_trusted_domain(struct imessaging_context
*msg
,
688 struct server_id server_id
,
691 TALLOC_CTX
*frame
= talloc_stackframe();
692 struct lsa_TrustDomainInfoInfoEx info
;
693 enum ndr_err_code ndr_err
;
694 struct winbindd_domain
*d
= NULL
;
696 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
703 ndr_err
= ndr_pull_struct_blob_all(data
, frame
, &info
,
704 (ndr_pull_flags_fn_t
)ndr_pull_lsa_TrustDomainInfoInfoEx
);
705 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
710 d
= find_domain_from_name_noinit(info
.netbios_name
.string
);
716 d
= add_trusted_domain(info
.netbios_name
.string
,
717 info
.domain_name
.string
,
734 if (info
.trust_direction
& LSA_TRUST_DIRECTION_INBOUND
) {
735 d
->domain_flags
|= NETR_TRUST_FLAG_INBOUND
;
737 if (info
.trust_direction
& LSA_TRUST_DIRECTION_OUTBOUND
) {
738 d
->domain_flags
|= NETR_TRUST_FLAG_OUTBOUND
;
740 if (info
.trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
741 d
->domain_flags
|= NETR_TRUST_FLAG_IN_FOREST
;
743 d
->domain_type
= info
.trust_type
;
744 d
->domain_trust_attribs
= info
.trust_attributes
;
750 * We did not get the secret when we queried secrets.tdb, so read it
751 * from secrets.tdb and re-sync the databases
753 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain
*domain
)
756 struct cli_credentials
*creds
;
757 NTSTATUS can_migrate
= pdb_get_trust_credentials(domain
->name
,
758 NULL
, domain
, &creds
);
759 if (!NT_STATUS_IS_OK(can_migrate
)) {
760 DEBUG(0, ("Failed to fetch our own, local AD domain join "
761 "password for winbindd's internal use, both from "
762 "secrets.tdb and secrets.ldb: %s\n",
763 nt_errstr(can_migrate
)));
768 * NOTE: It is very unlikely we end up here if there is an
769 * oldpass, because a new password is created at
770 * classicupgrade, so this is not a concern.
772 ok
= secrets_store_machine_pw_sync(cli_credentials_get_password(creds
),
774 cli_credentials_get_domain(creds
),
775 cli_credentials_get_realm(creds
),
776 cli_credentials_get_salt_principal(creds
),
777 0, /* Supported enc types, unused */
779 cli_credentials_get_password_last_changed_time(creds
),
780 cli_credentials_get_secure_channel_type(creds
),
781 false /* do_delete: Do not delete */);
784 DEBUG(0, ("Failed to write our our own, "
785 "local AD domain join password for "
786 "winbindd's internal use into secrets.tdb\n"));
792 /* Look up global info for the winbind daemon */
793 bool init_domain_list(void)
795 int role
= lp_server_role();
796 struct pdb_domain_info
*pdb_domain_info
= NULL
;
799 /* Free existing list */
804 (void)add_trusted_domain("BUILTIN", NULL
, &global_sid_Builtin
);
809 * In case the passdb backend is passdb_dsdb the domain SID comes from
810 * dsdb, not from secrets.tdb. As we use the domain SID in various
811 * places, we must ensure the domain SID is migrated from dsdb to
812 * secrets.tdb before get_global_sam_sid() is called the first time.
814 * The migration is done as part of the passdb_dsdb initialisation,
815 * calling pdb_get_domain_info() triggers it.
817 pdb_domain_info
= pdb_get_domain_info(talloc_tos());
819 if ( role
== ROLE_ACTIVE_DIRECTORY_DC
) {
820 struct winbindd_domain
*domain
;
821 enum netr_SchannelType sec_chan_type
;
822 const char *account_name
;
823 struct samr_Password current_nt_hash
;
826 if (pdb_domain_info
== NULL
) {
827 DEBUG(0, ("Failed to fetch our own, local AD "
828 "domain info from sam.ldb\n"));
831 domain
= add_trusted_domain(pdb_domain_info
->name
,
832 pdb_domain_info
->dns_domain
,
833 &pdb_domain_info
->sid
);
834 TALLOC_FREE(pdb_domain_info
);
835 if (domain
== NULL
) {
836 DEBUG(0, ("Failed to add our own, local AD "
837 "domain to winbindd's internal list\n"));
842 * We need to call this to find out if we are an RODC
844 ok
= get_trust_pw_hash(domain
->name
,
845 current_nt_hash
.hash
,
850 * If get_trust_pw_hash() fails, then try and
851 * fetch the password from the more recent of
852 * secrets.{ldb,tdb} using the
853 * pdb_get_trust_credentials()
855 ok
= migrate_secrets_tdb_to_ldb(domain
);
858 DEBUG(0, ("Failed to migrate our own, "
859 "local AD domain join password for "
860 "winbindd's internal use into "
864 ok
= get_trust_pw_hash(domain
->name
,
865 current_nt_hash
.hash
,
869 DEBUG(0, ("Failed to find our our own, just "
870 "written local AD domain join "
871 "password for winbindd's internal "
872 "use in secrets.tdb\n"));
876 if (sec_chan_type
== SEC_CHAN_RODC
) {
881 (void)add_trusted_domain(get_global_sam_name(), NULL
,
882 get_global_sam_sid());
884 /* Add ourselves as the first entry. */
886 if ( role
== ROLE_DOMAIN_MEMBER
) {
887 struct winbindd_domain
*domain
;
888 struct dom_sid our_sid
;
890 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid
)) {
891 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
895 domain
= add_trusted_domain(lp_workgroup(), lp_realm(),
898 /* Even in the parent winbindd we'll need to
899 talk to the DC, so try and see if we can
900 contact it. Theoretically this isn't neccessary
901 as the init_dc_connection() in init_child_recv()
902 will do this, but we can start detecting the DC
904 set_domain_online_request(domain
);
908 status
= imessaging_register(winbind_imessaging_context(), NULL
,
909 MSG_WINBIND_NEW_TRUSTED_DOMAIN
,
910 wb_imsg_new_trusted_domain
);
911 if (!NT_STATUS_IS_OK(status
)) {
912 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
921 * Given a domain name, return the struct winbindd domain info for it
923 * @note Do *not* pass lp_workgroup() to this function. domain_list
924 * may modify it's value, and free that pointer. Instead, our local
925 * domain may be found by calling find_our_domain().
929 * @return The domain structure for the named domain, if it is working.
932 struct winbindd_domain
*find_domain_from_name_noinit(const char *domain_name
)
934 struct winbindd_domain
*domain
;
936 /* Search through list */
938 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
939 if (strequal(domain_name
, domain
->name
) ||
940 (domain
->alt_name
!= NULL
&&
941 strequal(domain_name
, domain
->alt_name
))) {
951 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
953 struct winbindd_domain
*domain
;
955 domain
= find_domain_from_name_noinit(domain_name
);
960 if (!domain
->initialized
)
961 init_dc_connection(domain
, false);
966 /* Given a domain sid, return the struct winbindd domain info for it */
968 struct winbindd_domain
*find_domain_from_sid_noinit(const struct dom_sid
*sid
)
970 struct winbindd_domain
*domain
;
972 /* Search through list */
974 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
975 if (dom_sid_compare_domain(sid
, &domain
->sid
) == 0)
984 /* Given a domain sid, return the struct winbindd domain info for it */
986 struct winbindd_domain
*find_domain_from_sid(const struct dom_sid
*sid
)
988 struct winbindd_domain
*domain
;
990 domain
= find_domain_from_sid_noinit(sid
);
995 if (!domain
->initialized
)
996 init_dc_connection(domain
, false);
1001 struct winbindd_domain
*find_our_domain(void)
1003 struct winbindd_domain
*domain
;
1005 /* Search through list */
1007 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
1008 if (domain
->primary
)
1012 smb_panic("Could not find our domain");
1016 /* Find the appropriate domain to lookup a name or SID */
1018 struct winbindd_domain
*find_lookup_domain_from_sid(const struct dom_sid
*sid
)
1020 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid
));
1023 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1027 if ( sid_check_is_in_unix_groups(sid
) ||
1028 sid_check_is_unix_groups(sid
) ||
1029 sid_check_is_in_unix_users(sid
) ||
1030 sid_check_is_unix_users(sid
) ||
1031 sid_check_is_wellknown_domain(sid
, NULL
) ||
1032 sid_check_is_in_wellknown_domain(sid
) )
1034 return find_domain_from_sid(get_global_sam_sid());
1037 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1038 * one to contact the external DC's. On member servers the internal
1039 * domains are different: These are part of the local SAM. */
1041 if (IS_DC
|| is_internal_domain(sid
) || is_in_internal_domain(sid
)) {
1042 DEBUG(10, ("calling find_domain_from_sid\n"));
1043 return find_domain_from_sid(sid
);
1046 /* On a member server a query for SID or name can always go to our
1049 DEBUG(10, ("calling find_our_domain\n"));
1050 return find_our_domain();
1053 struct winbindd_domain
*find_lookup_domain_from_name(const char *domain_name
)
1055 if ( strequal(domain_name
, unix_users_domain_name() ) ||
1056 strequal(domain_name
, unix_groups_domain_name() ) )
1059 * The "Unix User" and "Unix Group" domain our handled by
1062 return find_domain_from_name_noinit( get_global_sam_name() );
1065 if (IS_DC
|| strequal(domain_name
, "BUILTIN") ||
1066 strequal(domain_name
, get_global_sam_name()))
1067 return find_domain_from_name_noinit(domain_name
);
1070 return find_our_domain();
1073 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1075 static bool assume_domain(const char *domain
)
1077 /* never assume the domain on a standalone server */
1079 if ( lp_server_role() == ROLE_STANDALONE
)
1082 /* domain member servers may possibly assume for the domain name */
1084 if ( lp_server_role() == ROLE_DOMAIN_MEMBER
) {
1085 if ( !strequal(lp_workgroup(), domain
) )
1088 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1092 /* only left with a domain controller */
1094 if ( strequal(get_global_sam_name(), domain
) ) {
1101 /* Parse a string of the form DOMAIN\user into a domain and a user */
1103 bool parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
1105 char *p
= strchr(domuser
,*lp_winbind_separator());
1108 fstrcpy(user
, domuser
);
1109 p
= strchr(domuser
, '@');
1111 if ( assume_domain(lp_workgroup()) && p
== NULL
) {
1112 fstrcpy(domain
, lp_workgroup());
1113 } else if (p
!= NULL
) {
1114 fstrcpy(domain
, p
+ 1);
1115 user
[PTR_DIFF(p
, domuser
)] = 0;
1121 fstrcpy(domain
, domuser
);
1122 domain
[PTR_DIFF(p
, domuser
)] = 0;
1125 return strupper_m(domain
);
1128 bool parse_domain_user_talloc(TALLOC_CTX
*mem_ctx
, const char *domuser
,
1129 char **domain
, char **user
)
1131 fstring fstr_domain
, fstr_user
;
1132 if (!parse_domain_user(domuser
, fstr_domain
, fstr_user
)) {
1135 *domain
= talloc_strdup(mem_ctx
, fstr_domain
);
1136 *user
= talloc_strdup(mem_ctx
, fstr_user
);
1137 return ((*domain
!= NULL
) && (*user
!= NULL
));
1140 /* Ensure an incoming username from NSS is fully qualified. Replace the
1141 incoming fstring with DOMAIN <separator> user. Returns the same
1142 values as parse_domain_user() but also replaces the incoming username.
1143 Used to ensure all names are fully qualified within winbindd.
1144 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1145 The protocol definitions of auth_crap, chng_pswd_auth_crap
1146 really should be changed to use this instead of doing things
1149 bool canonicalize_username(fstring username_inout
, fstring domain
, fstring user
)
1151 if (!parse_domain_user(username_inout
, domain
, user
)) {
1154 slprintf(username_inout
, sizeof(fstring
) - 1, "%s%c%s",
1155 domain
, *lp_winbind_separator(),
1161 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1162 'winbind separator' options.
1164 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1167 If we are a PDC or BDC, and this is for our domain, do likewise.
1169 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1170 username is then unqualified in unix
1172 On an AD DC we always fill DOMAIN\\USERNAME.
1174 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1176 void fill_domain_username(fstring name
, const char *domain
, const char *user
, bool can_assume
)
1180 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
) {
1184 fstrcpy(tmp_user
, user
);
1185 (void)strlower_m(tmp_user
);
1187 if (can_assume
&& assume_domain(domain
)) {
1188 strlcpy(name
, tmp_user
, sizeof(fstring
));
1190 slprintf(name
, sizeof(fstring
) - 1, "%s%c%s",
1191 domain
, *lp_winbind_separator(),
1197 * talloc version of fill_domain_username()
1198 * return NULL on talloc failure.
1200 char *fill_domain_username_talloc(TALLOC_CTX
*mem_ctx
,
1205 char *tmp_user
, *name
;
1207 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
) {
1211 tmp_user
= talloc_strdup(mem_ctx
, user
);
1212 if (!strlower_m(tmp_user
)) {
1213 TALLOC_FREE(tmp_user
);
1217 if (can_assume
&& assume_domain(domain
)) {
1220 name
= talloc_asprintf(mem_ctx
, "%s%c%s",
1222 *lp_winbind_separator(),
1224 TALLOC_FREE(tmp_user
);
1231 * Client list accessor functions
1234 static struct winbindd_cli_state
*_client_list
;
1235 static int _num_clients
;
1237 /* Return list of all connected clients */
1239 struct winbindd_cli_state
*winbindd_client_list(void)
1241 return _client_list
;
1244 /* Return list-tail of all connected clients */
1246 struct winbindd_cli_state
*winbindd_client_list_tail(void)
1248 return DLIST_TAIL(_client_list
);
1251 /* Return previous (read:newer) client in list */
1253 struct winbindd_cli_state
*
1254 winbindd_client_list_prev(struct winbindd_cli_state
*cli
)
1256 return DLIST_PREV(cli
);
1259 /* Add a connection to the list */
1261 void winbindd_add_client(struct winbindd_cli_state
*cli
)
1263 cli
->last_access
= time(NULL
);
1264 DLIST_ADD(_client_list
, cli
);
1268 /* Remove a client from the list */
1270 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
1272 DLIST_REMOVE(_client_list
, cli
);
1276 /* Move a client to head or list */
1278 void winbindd_promote_client(struct winbindd_cli_state
*cli
)
1280 cli
->last_access
= time(NULL
);
1281 DLIST_PROMOTE(_client_list
, cli
);
1284 /* Return number of open clients */
1286 int winbindd_num_clients(void)
1288 return _num_clients
;
1291 NTSTATUS
lookup_usergroups_cached(TALLOC_CTX
*mem_ctx
,
1292 const struct dom_sid
*user_sid
,
1293 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
1295 struct netr_SamInfo3
*info3
= NULL
;
1296 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1297 uint32_t num_groups
= 0;
1299 DEBUG(3,(": lookup_usergroups_cached\n"));
1304 info3
= netsamlogon_cache_get(mem_ctx
, user_sid
);
1306 if (info3
== NULL
) {
1307 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1311 * Before bug #7843 the "Domain Local" groups were added with a
1312 * lookupuseraliases call, but this isn't done anymore for our domain
1313 * so we need to resolve resource groups here.
1315 * When to use Resource Groups:
1316 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1318 status
= sid_array_from_info3(mem_ctx
, info3
,
1323 if (!NT_STATUS_IS_OK(status
)) {
1329 *p_num_groups
= num_groups
;
1330 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1332 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1337 /*********************************************************************
1338 We use this to remove spaces from user and group names
1339 ********************************************************************/
1341 NTSTATUS
normalize_name_map(TALLOC_CTX
*mem_ctx
,
1342 struct winbindd_domain
*domain
,
1348 if (!name
|| !normalized
) {
1349 return NT_STATUS_INVALID_PARAMETER
;
1352 if (!lp_winbind_normalize_names()) {
1353 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1356 /* Alias support and whitespace replacement are mutually
1359 nt_status
= resolve_username_to_alias(mem_ctx
, domain
,
1361 if (NT_STATUS_IS_OK(nt_status
)) {
1362 /* special return code to let the caller know we
1363 mapped to an alias */
1364 return NT_STATUS_FILE_RENAMED
;
1367 /* check for an unreachable domain */
1369 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1370 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1372 set_domain_offline(domain
);
1376 /* deal with whitespace */
1378 *normalized
= talloc_strdup(mem_ctx
, name
);
1379 if (!(*normalized
)) {
1380 return NT_STATUS_NO_MEMORY
;
1383 all_string_sub( *normalized
, " ", "_", 0 );
1385 return NT_STATUS_OK
;
1388 /*********************************************************************
1389 We use this to do the inverse of normalize_name_map()
1390 ********************************************************************/
1392 NTSTATUS
normalize_name_unmap(TALLOC_CTX
*mem_ctx
,
1397 struct winbindd_domain
*domain
= find_our_domain();
1399 if (!name
|| !normalized
) {
1400 return NT_STATUS_INVALID_PARAMETER
;
1403 if (!lp_winbind_normalize_names()) {
1404 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1407 /* Alias support and whitespace replacement are mutally
1410 /* When mapping from an alias to a username, we don't know the
1411 domain. But we only need a domain structure to cache
1412 a successful lookup , so just our own domain structure for
1415 nt_status
= resolve_alias_to_username(mem_ctx
, domain
,
1417 if (NT_STATUS_IS_OK(nt_status
)) {
1418 /* Special return code to let the caller know we mapped
1420 return NT_STATUS_FILE_RENAMED
;
1423 /* check for an unreachable domain */
1425 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1426 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1428 set_domain_offline(domain
);
1432 /* deal with whitespace */
1434 *normalized
= talloc_strdup(mem_ctx
, name
);
1435 if (!(*normalized
)) {
1436 return NT_STATUS_NO_MEMORY
;
1439 all_string_sub(*normalized
, "_", " ", 0);
1441 return NT_STATUS_OK
;
1444 /*********************************************************************
1445 ********************************************************************/
1447 bool winbindd_can_contact_domain(struct winbindd_domain
*domain
)
1449 struct winbindd_tdc_domain
*tdc
= NULL
;
1450 TALLOC_CTX
*frame
= talloc_stackframe();
1453 /* We can contact the domain if it is our primary domain */
1455 if (domain
->primary
) {
1460 /* Trust the TDC cache and not the winbindd_domain flags */
1462 if ((tdc
= wcache_tdc_fetch_domain(frame
, domain
->name
)) == NULL
) {
1463 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1469 /* Can always contact a domain that is in out forest */
1471 if (tdc
->trust_flags
& NETR_TRUST_FLAG_IN_FOREST
) {
1477 * On a _member_ server, we cannot contact the domain if it
1478 * is running AD and we have no inbound trust.
1482 domain
->active_directory
&&
1483 ((tdc
->trust_flags
& NETR_TRUST_FLAG_INBOUND
) != NETR_TRUST_FLAG_INBOUND
))
1485 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1486 "and we have no inbound trust.\n", domain
->name
));
1490 /* Assume everything else is ok (probably not true but what
1496 talloc_destroy(frame
);
1501 /*********************************************************************
1502 ********************************************************************/
1504 bool winbindd_internal_child(struct winbindd_child
*child
)
1506 if ((child
== idmap_child()) || (child
== locator_child())) {
1513 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1515 /*********************************************************************
1516 ********************************************************************/
1518 static void winbindd_set_locator_kdc_env(const struct winbindd_domain
*domain
)
1521 char addr
[INET6_ADDRSTRLEN
];
1522 const char *kdc
= NULL
;
1525 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1529 if (domain
->initialized
&& !domain
->active_directory
) {
1530 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s not AD\n",
1535 print_sockaddr(addr
, sizeof(addr
), &domain
->dcaddr
);
1538 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1540 kdc
= domain
->dcname
;
1543 if (!kdc
|| !*kdc
) {
1544 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1549 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1550 domain
->alt_name
) == -1) {
1554 DEBUG(lvl
,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1557 setenv(var
, kdc
, 1);
1561 /*********************************************************************
1562 ********************************************************************/
1564 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1566 struct winbindd_domain
*our_dom
= find_our_domain();
1568 winbindd_set_locator_kdc_env(domain
);
1570 if (domain
!= our_dom
) {
1571 winbindd_set_locator_kdc_env(our_dom
);
1575 /*********************************************************************
1576 ********************************************************************/
1578 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1582 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1586 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1587 domain
->alt_name
) == -1) {
1596 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1601 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1606 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1608 void set_auth_errors(struct winbindd_response
*resp
, NTSTATUS result
)
1610 resp
->data
.auth
.nt_status
= NT_STATUS_V(result
);
1611 fstrcpy(resp
->data
.auth
.nt_status_string
, nt_errstr(result
));
1613 /* we might have given a more useful error above */
1614 if (*resp
->data
.auth
.error_string
== '\0')
1615 fstrcpy(resp
->data
.auth
.error_string
,
1616 get_friendly_nt_error_msg(result
));
1617 resp
->data
.auth
.pam_error
= nt_status_to_pam(result
);
1620 bool is_domain_offline(const struct winbindd_domain
*domain
)
1622 if (!lp_winbind_offline_logon()) {
1625 if (get_global_winbindd_state_offline()) {
1628 return !domain
->online
;
1631 bool is_domain_online(const struct winbindd_domain
*domain
)
1633 return !is_domain_offline(domain
);
1637 * Parse an char array into a list of sids.
1639 * The input sidstr should consist of 0-terminated strings
1640 * representing sids, separated by newline characters '\n'.
1641 * The list is terminated by an empty string, i.e.
1642 * character '\0' directly following a character '\n'
1643 * (or '\0' right at the start of sidstr).
1645 bool parse_sidlist(TALLOC_CTX
*mem_ctx
, const char *sidstr
,
1646 struct dom_sid
**sids
, uint32_t *num_sids
)
1654 while (p
[0] != '\0') {
1656 const char *q
= NULL
;
1658 if (!dom_sid_parse_endp(p
, &sid
, &q
)) {
1659 DEBUG(1, ("Could not parse sid %s\n", p
));
1663 DEBUG(1, ("Got invalid sidstr: %s\n", p
));
1666 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx
, &sid
, sids
,
1676 bool parse_xidlist(TALLOC_CTX
*mem_ctx
, const char *xidstr
,
1677 struct unixid
**pxids
, uint32_t *pnum_xids
)
1680 struct unixid
*xids
= NULL
;
1681 uint32_t num_xids
= 0;
1688 while (p
[0] != '\0') {
1691 unsigned long long id
;
1696 xid
= (struct unixid
) { .type
= ID_TYPE_UID
};
1699 xid
= (struct unixid
) { .type
= ID_TYPE_GID
};
1707 id
= strtoull(p
, &endp
, 10);
1708 if ((id
== ULLONG_MAX
) && (errno
== ERANGE
)) {
1711 if (*endp
!= '\n') {
1717 if ((unsigned long long)xid
.id
!= id
) {
1721 tmp
= talloc_realloc(mem_ctx
, xids
, struct unixid
, num_xids
+1);
1727 xids
[num_xids
] = xid
;
1732 *pnum_xids
= num_xids
;