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
)) {
156 DBG_ERR("Got null SID for domain [%s]\n", domain_name
);
160 ignored_domains
= lp_parm_string_list(-1, "winbind", "ignore domains", NULL
);
161 for (dom
=ignored_domains
; dom
&& *dom
; dom
++) {
162 if (gen_fnmatch(*dom
, domain_name
) == 0) {
163 DEBUG(2,("Ignoring domain '%s'\n", domain_name
));
168 /* use alt_name if available to allow DNS lookups */
170 if (tdc
->dns_name
&& *tdc
->dns_name
) {
171 alternative_name
= tdc
->dns_name
;
174 /* We can't call domain_list() as this function is called from
175 init_domain_list() and we'll get stuck in a loop. */
176 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
177 if (strequal(domain_name
, domain
->name
)) {
182 if (domain
!= NULL
) {
183 struct winbindd_domain
*check_domain
= NULL
;
185 for (check_domain
= _domain_list
;
186 check_domain
!= NULL
;
187 check_domain
= check_domain
->next
)
189 if (check_domain
== domain
) {
193 if (dom_sid_equal(&check_domain
->sid
, sid
)) {
198 if (check_domain
!= NULL
) {
199 DBG_ERR("SID [%s] already used by domain [%s], "
201 sid_string_dbg(sid
), check_domain
->name
,
207 if ((domain
!= NULL
) && (alternative_name
!= NULL
)) {
208 struct winbindd_domain
*check_domain
= NULL
;
210 for (check_domain
= _domain_list
;
211 check_domain
!= NULL
;
212 check_domain
= check_domain
->next
)
214 if (check_domain
== domain
) {
218 if (strequal(check_domain
->alt_name
, alternative_name
)) {
223 if (check_domain
!= NULL
) {
224 DBG_ERR("DNS name [%s] used by domain [%s], "
226 alternative_name
, check_domain
->name
,
232 if (domain
!= NULL
) {
236 /* Create new domain entry */
237 domain
= talloc_zero(NULL
, struct winbindd_domain
);
238 if (domain
== NULL
) {
242 domain
->children
= talloc_zero_array(domain
,
243 struct winbindd_child
,
244 lp_winbind_max_domain_connections());
245 if (domain
->children
== NULL
) {
250 domain
->name
= talloc_strdup(domain
, domain_name
);
251 if (domain
->name
== NULL
) {
256 if (alternative_name
) {
257 domain
->alt_name
= talloc_strdup(domain
, alternative_name
);
258 if (domain
->alt_name
== NULL
) {
264 domain
->backend
= NULL
;
265 domain
->internal
= is_internal_domain(sid
);
266 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
267 domain
->last_seq_check
= 0;
268 domain
->initialized
= false;
269 domain
->online
= is_internal_domain(sid
);
270 domain
->check_online_timeout
= 0;
271 domain
->dc_probe_pid
= (pid_t
)-1;
272 domain
->domain_flags
= tdc
->trust_flags
;
273 domain
->domain_type
= tdc
->trust_type
;
274 domain
->domain_trust_attribs
= tdc
->trust_attribs
;
275 sid_copy(&domain
->sid
, sid
);
277 /* Is this our primary domain ? */
278 if (role
== ROLE_DOMAIN_MEMBER
) {
279 domain
->primary
= strequal(domain_name
, lp_workgroup());
281 domain
->primary
= strequal(domain_name
, get_global_sam_name());
284 if (domain
->primary
) {
285 if (role
== ROLE_ACTIVE_DIRECTORY_DC
) {
286 domain
->active_directory
= true;
288 if (lp_security() == SEC_ADS
) {
289 domain
->active_directory
= true;
291 } else if (!domain
->internal
) {
292 if (domain
->domain_type
== LSA_TRUST_TYPE_UPLEVEL
) {
293 domain
->active_directory
= true;
297 /* Link to domain list */
298 DLIST_ADD_END(_domain_list
, domain
);
300 wcache_tdc_add_domain( domain
);
302 setup_domain_child(domain
);
305 ("Added domain %s %s %s\n", domain
->name
, domain
->alt_name
,
306 !is_null_sid(&domain
->sid
) ? sid_string_dbg(&domain
->sid
) : ""));
311 bool domain_is_forest_root(const struct winbindd_domain
*domain
)
313 const uint32_t fr_flags
=
314 (NETR_TRUST_FLAG_TREEROOT
|NETR_TRUST_FLAG_IN_FOREST
);
316 return ((domain
->domain_flags
& fr_flags
) == fr_flags
);
319 /********************************************************************
320 rescan our domains looking for new trusted domains
321 ********************************************************************/
323 struct trustdom_state
{
324 struct winbindd_domain
*domain
;
325 struct winbindd_request request
;
328 static void trustdom_list_done(struct tevent_req
*req
);
329 static void rescan_forest_root_trusts( void );
330 static void rescan_forest_trusts( void );
332 static void add_trusted_domains( struct winbindd_domain
*domain
)
334 struct trustdom_state
*state
;
335 struct tevent_req
*req
;
337 state
= talloc_zero(NULL
, struct trustdom_state
);
339 DEBUG(0, ("talloc failed\n"));
342 state
->domain
= domain
;
344 state
->request
.length
= sizeof(state
->request
);
345 state
->request
.cmd
= WINBINDD_LIST_TRUSTDOM
;
347 req
= wb_domain_request_send(state
, server_event_context(),
348 domain
, &state
->request
);
350 DEBUG(1, ("wb_domain_request_send failed\n"));
354 tevent_req_set_callback(req
, trustdom_list_done
, state
);
357 static void trustdom_list_done(struct tevent_req
*req
)
359 struct trustdom_state
*state
= tevent_req_callback_data(
360 req
, struct trustdom_state
);
361 struct winbindd_response
*response
;
364 struct winbindd_tdc_domain trust_params
= {0};
366 bool within_forest
= false;
369 * Only when we enumerate our primary domain
370 * or our forest root domain, we should keep
371 * the NETR_TRUST_FLAG_IN_FOREST flag, in
372 * all other cases we need to clear it as the domain
373 * is not part of our forest.
375 if (state
->domain
->primary
) {
376 within_forest
= true;
377 } else if (domain_is_forest_root(state
->domain
)) {
378 within_forest
= true;
381 res
= wb_domain_request_recv(req
, state
, &response
, &err
);
382 if ((res
== -1) || (response
->result
!= WINBINDD_OK
)) {
383 DBG_WARNING("Could not receive trusts for domain %s\n",
384 state
->domain
->name
);
389 if (response
->length
< sizeof(struct winbindd_response
)) {
390 DBG_ERR("ill-formed trustdom response - short length\n");
395 extra_len
= response
->length
- sizeof(struct winbindd_response
);
397 p
= (char *)response
->extra_data
.data
;
399 while ((p
- (char *)response
->extra_data
.data
) < extra_len
) {
400 char *q
, *sidstr
, *alt_name
;
402 DBG_DEBUG("parsing response line '%s'\n", p
);
404 ZERO_STRUCT(trust_params
);
405 trust_params
.domain_name
= p
;
407 alt_name
= strchr(p
, '\\');
408 if (alt_name
== NULL
) {
409 DBG_ERR("Got invalid trustdom response\n");
416 sidstr
= strchr(alt_name
, '\\');
417 if (sidstr
== NULL
) {
418 DBG_ERR("Got invalid trustdom response\n");
425 /* use the real alt_name if we have one, else pass in NULL */
426 if (!strequal(alt_name
, "(null)")) {
427 trust_params
.dns_name
= alt_name
;
430 q
= strtok(sidstr
, "\\");
432 DBG_ERR("Got invalid trustdom response\n");
436 if (!string_to_sid(&trust_params
.sid
, sidstr
)) {
437 DEBUG(0, ("Got invalid trustdom response\n"));
441 q
= strtok(NULL
, "\\");
443 DBG_ERR("Got invalid trustdom response\n");
447 trust_params
.trust_flags
= (uint32_t)strtoul(q
, NULL
, 10);
449 q
= strtok(NULL
, "\\");
451 DBG_ERR("Got invalid trustdom response\n");
455 trust_params
.trust_type
= (uint32_t)strtoul(q
, NULL
, 10);
457 q
= strtok(NULL
, "\n");
459 DBG_ERR("Got invalid trustdom response\n");
463 trust_params
.trust_attribs
= (uint32_t)strtoul(q
, NULL
, 10);
465 if (!within_forest
) {
466 trust_params
.trust_flags
&= ~NETR_TRUST_FLAG_IN_FOREST
;
469 if (!state
->domain
->primary
) {
470 trust_params
.trust_flags
&= ~NETR_TRUST_FLAG_PRIMARY
;
474 * We always call add_trusted_domain() cause on an existing
475 * domain structure, it will update the SID if necessary.
476 * This is important because we need the SID for sibling
479 (void)add_trusted_domain_from_tdc(&trust_params
);
481 p
= q
+ strlen(q
) + 1;
485 Cases to consider when scanning trusts:
486 (a) we are calling from a child domain (primary && !forest_root)
487 (b) we are calling from the root of the forest (primary && forest_root)
488 (c) we are calling from a trusted forest domain (!primary
492 if (state
->domain
->primary
) {
493 /* If this is our primary domain and we are not in the
494 forest root, we have to scan the root trusts first */
496 if (!domain_is_forest_root(state
->domain
))
497 rescan_forest_root_trusts();
499 rescan_forest_trusts();
501 } else if (domain_is_forest_root(state
->domain
)) {
502 /* Once we have done root forest trust search, we can
503 go on to search the trusted forests */
505 rescan_forest_trusts();
513 /********************************************************************
514 Scan the trusts of our forest root
515 ********************************************************************/
517 static void rescan_forest_root_trusts( void )
519 struct winbindd_tdc_domain
*dom_list
= NULL
;
520 size_t num_trusts
= 0;
523 /* The only transitive trusts supported by Windows 2003 AD are
524 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
525 first two are handled in forest and listed by
526 DsEnumerateDomainTrusts(). Forest trusts are not so we
527 have to do that ourselves. */
529 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
532 for ( i
=0; i
<num_trusts
; i
++ ) {
533 struct winbindd_domain
*d
= NULL
;
535 /* Find the forest root. Don't necessarily trust
536 the domain_list() as our primary domain may not
537 have been initialized. */
539 if ( !(dom_list
[i
].trust_flags
& NETR_TRUST_FLAG_TREEROOT
) ) {
543 /* Here's the forest root */
545 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
548 d
= add_trusted_domain_from_tdc(&dom_list
[i
]);
555 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
556 "for domain tree root %s (%s)\n",
557 d
->name
, d
->alt_name
));
559 d
->domain_flags
= dom_list
[i
].trust_flags
;
560 d
->domain_type
= dom_list
[i
].trust_type
;
561 d
->domain_trust_attribs
= dom_list
[i
].trust_attribs
;
563 add_trusted_domains( d
);
568 TALLOC_FREE( dom_list
);
573 /********************************************************************
574 scan the transitive forest trusts (not our own)
575 ********************************************************************/
578 static void rescan_forest_trusts( void )
580 struct winbindd_domain
*d
= NULL
;
581 struct winbindd_tdc_domain
*dom_list
= NULL
;
582 size_t num_trusts
= 0;
585 /* The only transitive trusts supported by Windows 2003 AD are
586 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
587 first two are handled in forest and listed by
588 DsEnumerateDomainTrusts(). Forest trusts are not so we
589 have to do that ourselves. */
591 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
594 for ( i
=0; i
<num_trusts
; i
++ ) {
595 uint32_t flags
= dom_list
[i
].trust_flags
;
596 uint32_t type
= dom_list
[i
].trust_type
;
597 uint32_t attribs
= dom_list
[i
].trust_attribs
;
599 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
601 /* ignore our primary and internal domains */
603 if ( d
&& (d
->internal
|| d
->primary
) )
606 if ( (flags
& NETR_TRUST_FLAG_INBOUND
) &&
607 (type
== LSA_TRUST_TYPE_UPLEVEL
) &&
608 (attribs
== LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) )
610 /* add the trusted domain if we don't know
614 d
= add_trusted_domain_from_tdc(&dom_list
[i
]);
621 DEBUG(10,("Following trust path for domain %s (%s)\n",
622 d
->name
, d
->alt_name
));
623 add_trusted_domains( d
);
627 TALLOC_FREE( dom_list
);
632 /*********************************************************************
633 The process of updating the trusted domain list is a three step
636 (b) ask the root domain in our forest
637 (c) ask the a DC in any Win2003 trusted forests
638 *********************************************************************/
640 void rescan_trusted_domains(struct tevent_context
*ev
, struct tevent_timer
*te
,
641 struct timeval now
, void *private_data
)
645 /* I use to clear the cache here and start over but that
646 caused problems in child processes that needed the
647 trust dom list early on. Removing it means we
648 could have some trusted domains listed that have been
649 removed from our primary domain's DC until a full
650 restart. This should be ok since I think this is what
651 Windows does as well. */
653 /* this will only add new domains we didn't already know about
654 in the domain_list()*/
656 add_trusted_domains( find_our_domain() );
658 te
= tevent_add_timer(
659 ev
, NULL
, timeval_current_ofs(WINBINDD_RESCAN_FREQ
, 0),
660 rescan_trusted_domains
, NULL
);
662 * If te == NULL, there's not much we can do here. Don't fail, the
663 * only thing we miss is new trusted domains.
669 enum winbindd_result
winbindd_dual_init_connection(struct winbindd_domain
*domain
,
670 struct winbindd_cli_state
*state
)
672 /* Ensure null termination */
673 state
->request
->domain_name
674 [sizeof(state
->request
->domain_name
)-1]='\0';
675 state
->request
->data
.init_conn
.dcname
676 [sizeof(state
->request
->data
.init_conn
.dcname
)-1]='\0';
678 if (strlen(state
->request
->data
.init_conn
.dcname
) > 0) {
679 fstrcpy(domain
->dcname
, state
->request
->data
.init_conn
.dcname
);
682 init_dc_connection(domain
, false);
684 if (!domain
->initialized
) {
685 /* If we return error here we can't do any cached authentication,
686 but we may be in disconnected mode and can't initialize correctly.
687 Do what the previous code did and just return without initialization,
688 once we go online we'll re-initialize.
690 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
691 "online = %d\n", domain
->name
, (int)domain
->online
));
694 fstrcpy(state
->response
->data
.domain_info
.name
, domain
->name
);
695 fstrcpy(state
->response
->data
.domain_info
.alt_name
, domain
->alt_name
);
696 sid_to_fstring(state
->response
->data
.domain_info
.sid
, &domain
->sid
);
698 state
->response
->data
.domain_info
.native_mode
699 = domain
->native_mode
;
700 state
->response
->data
.domain_info
.active_directory
701 = domain
->active_directory
;
702 state
->response
->data
.domain_info
.primary
708 static void wb_imsg_new_trusted_domain(struct imessaging_context
*msg
,
711 struct server_id server_id
,
714 TALLOC_CTX
*frame
= talloc_stackframe();
715 struct lsa_TrustDomainInfoInfoEx info
;
716 enum ndr_err_code ndr_err
;
717 struct winbindd_domain
*d
= NULL
;
719 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
726 ndr_err
= ndr_pull_struct_blob_all(data
, frame
, &info
,
727 (ndr_pull_flags_fn_t
)ndr_pull_lsa_TrustDomainInfoInfoEx
);
728 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
733 d
= find_domain_from_name_noinit(info
.netbios_name
.string
);
739 d
= add_trusted_domain(info
.netbios_name
.string
,
740 info
.domain_name
.string
,
757 if (info
.trust_direction
& LSA_TRUST_DIRECTION_INBOUND
) {
758 d
->domain_flags
|= NETR_TRUST_FLAG_INBOUND
;
760 if (info
.trust_direction
& LSA_TRUST_DIRECTION_OUTBOUND
) {
761 d
->domain_flags
|= NETR_TRUST_FLAG_OUTBOUND
;
763 if (info
.trust_attributes
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
764 d
->domain_flags
|= NETR_TRUST_FLAG_IN_FOREST
;
766 d
->domain_type
= info
.trust_type
;
767 d
->domain_trust_attribs
= info
.trust_attributes
;
773 * We did not get the secret when we queried secrets.tdb, so read it
774 * from secrets.tdb and re-sync the databases
776 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain
*domain
)
779 struct cli_credentials
*creds
;
780 NTSTATUS can_migrate
= pdb_get_trust_credentials(domain
->name
,
781 NULL
, domain
, &creds
);
782 if (!NT_STATUS_IS_OK(can_migrate
)) {
783 DEBUG(0, ("Failed to fetch our own, local AD domain join "
784 "password for winbindd's internal use, both from "
785 "secrets.tdb and secrets.ldb: %s\n",
786 nt_errstr(can_migrate
)));
791 * NOTE: It is very unlikely we end up here if there is an
792 * oldpass, because a new password is created at
793 * classicupgrade, so this is not a concern.
795 ok
= secrets_store_machine_pw_sync(cli_credentials_get_password(creds
),
797 cli_credentials_get_domain(creds
),
798 cli_credentials_get_realm(creds
),
799 cli_credentials_get_salt_principal(creds
),
800 0, /* Supported enc types, unused */
802 cli_credentials_get_password_last_changed_time(creds
),
803 cli_credentials_get_secure_channel_type(creds
),
804 false /* do_delete: Do not delete */);
807 DEBUG(0, ("Failed to write our our own, "
808 "local AD domain join password for "
809 "winbindd's internal use into secrets.tdb\n"));
815 /* Look up global info for the winbind daemon */
816 bool init_domain_list(void)
818 int role
= lp_server_role();
819 struct pdb_domain_info
*pdb_domain_info
= NULL
;
822 /* Free existing list */
827 (void)add_trusted_domain("BUILTIN", NULL
, &global_sid_Builtin
);
832 * In case the passdb backend is passdb_dsdb the domain SID comes from
833 * dsdb, not from secrets.tdb. As we use the domain SID in various
834 * places, we must ensure the domain SID is migrated from dsdb to
835 * secrets.tdb before get_global_sam_sid() is called the first time.
837 * The migration is done as part of the passdb_dsdb initialisation,
838 * calling pdb_get_domain_info() triggers it.
840 pdb_domain_info
= pdb_get_domain_info(talloc_tos());
842 if ( role
== ROLE_ACTIVE_DIRECTORY_DC
) {
843 struct winbindd_domain
*domain
;
844 enum netr_SchannelType sec_chan_type
;
845 const char *account_name
;
846 struct samr_Password current_nt_hash
;
849 if (pdb_domain_info
== NULL
) {
850 DEBUG(0, ("Failed to fetch our own, local AD "
851 "domain info from sam.ldb\n"));
854 domain
= add_trusted_domain(pdb_domain_info
->name
,
855 pdb_domain_info
->dns_domain
,
856 &pdb_domain_info
->sid
);
857 TALLOC_FREE(pdb_domain_info
);
858 if (domain
== NULL
) {
859 DEBUG(0, ("Failed to add our own, local AD "
860 "domain to winbindd's internal list\n"));
865 * We need to call this to find out if we are an RODC
867 ok
= get_trust_pw_hash(domain
->name
,
868 current_nt_hash
.hash
,
873 * If get_trust_pw_hash() fails, then try and
874 * fetch the password from the more recent of
875 * secrets.{ldb,tdb} using the
876 * pdb_get_trust_credentials()
878 ok
= migrate_secrets_tdb_to_ldb(domain
);
881 DEBUG(0, ("Failed to migrate our own, "
882 "local AD domain join password for "
883 "winbindd's internal use into "
887 ok
= get_trust_pw_hash(domain
->name
,
888 current_nt_hash
.hash
,
892 DEBUG(0, ("Failed to find our our own, just "
893 "written local AD domain join "
894 "password for winbindd's internal "
895 "use in secrets.tdb\n"));
899 if (sec_chan_type
== SEC_CHAN_RODC
) {
904 (void)add_trusted_domain(get_global_sam_name(), NULL
,
905 get_global_sam_sid());
907 /* Add ourselves as the first entry. */
909 if ( role
== ROLE_DOMAIN_MEMBER
) {
910 struct winbindd_domain
*domain
;
911 struct dom_sid our_sid
;
913 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid
)) {
914 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
918 domain
= add_trusted_domain(lp_workgroup(), lp_realm(),
921 /* Even in the parent winbindd we'll need to
922 talk to the DC, so try and see if we can
923 contact it. Theoretically this isn't neccessary
924 as the init_dc_connection() in init_child_recv()
925 will do this, but we can start detecting the DC
927 set_domain_online_request(domain
);
931 status
= imessaging_register(winbind_imessaging_context(), NULL
,
932 MSG_WINBIND_NEW_TRUSTED_DOMAIN
,
933 wb_imsg_new_trusted_domain
);
934 if (!NT_STATUS_IS_OK(status
)) {
935 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
944 * Given a domain name, return the struct winbindd domain info for it
946 * @note Do *not* pass lp_workgroup() to this function. domain_list
947 * may modify it's value, and free that pointer. Instead, our local
948 * domain may be found by calling find_our_domain().
952 * @return The domain structure for the named domain, if it is working.
955 struct winbindd_domain
*find_domain_from_name_noinit(const char *domain_name
)
957 struct winbindd_domain
*domain
;
959 /* Search through list */
961 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
962 if (strequal(domain_name
, domain
->name
)) {
965 if (domain
->alt_name
== NULL
) {
968 if (strequal(domain_name
, domain
->alt_name
)) {
978 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
980 struct winbindd_domain
*domain
;
982 domain
= find_domain_from_name_noinit(domain_name
);
987 if (!domain
->initialized
)
988 init_dc_connection(domain
, false);
993 /* Given a domain sid, return the struct winbindd domain info for it */
995 struct winbindd_domain
*find_domain_from_sid_noinit(const struct dom_sid
*sid
)
997 struct winbindd_domain
*domain
;
999 /* Search through list */
1001 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
1002 if (dom_sid_compare_domain(sid
, &domain
->sid
) == 0)
1011 /* Given a domain sid, return the struct winbindd domain info for it */
1013 struct winbindd_domain
*find_domain_from_sid(const struct dom_sid
*sid
)
1015 struct winbindd_domain
*domain
;
1017 domain
= find_domain_from_sid_noinit(sid
);
1022 if (!domain
->initialized
)
1023 init_dc_connection(domain
, false);
1028 struct winbindd_domain
*find_our_domain(void)
1030 struct winbindd_domain
*domain
;
1032 /* Search through list */
1034 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
1035 if (domain
->primary
)
1039 smb_panic("Could not find our domain");
1043 /* Find the appropriate domain to lookup a name or SID */
1045 struct winbindd_domain
*find_lookup_domain_from_sid(const struct dom_sid
*sid
)
1047 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid
));
1050 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1054 if ( sid_check_is_in_unix_groups(sid
) ||
1055 sid_check_is_unix_groups(sid
) ||
1056 sid_check_is_in_unix_users(sid
) ||
1057 sid_check_is_unix_users(sid
) ||
1058 sid_check_is_wellknown_domain(sid
, NULL
) ||
1059 sid_check_is_in_wellknown_domain(sid
) )
1061 return find_domain_from_sid(get_global_sam_sid());
1064 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1065 * one to contact the external DC's. On member servers the internal
1066 * domains are different: These are part of the local SAM. */
1068 if (IS_DC
|| is_internal_domain(sid
) || is_in_internal_domain(sid
)) {
1069 DEBUG(10, ("calling find_domain_from_sid\n"));
1070 return find_domain_from_sid(sid
);
1073 /* On a member server a query for SID or name can always go to our
1076 DEBUG(10, ("calling find_our_domain\n"));
1077 return find_our_domain();
1080 struct winbindd_domain
*find_lookup_domain_from_name(const char *domain_name
)
1082 if ( strequal(domain_name
, unix_users_domain_name() ) ||
1083 strequal(domain_name
, unix_groups_domain_name() ) )
1086 * The "Unix User" and "Unix Group" domain our handled by
1089 return find_domain_from_name_noinit( get_global_sam_name() );
1092 if (IS_DC
|| strequal(domain_name
, "BUILTIN") ||
1093 strequal(domain_name
, get_global_sam_name()))
1094 return find_domain_from_name_noinit(domain_name
);
1097 return find_our_domain();
1100 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1102 static bool assume_domain(const char *domain
)
1104 /* never assume the domain on a standalone server */
1106 if ( lp_server_role() == ROLE_STANDALONE
)
1109 /* domain member servers may possibly assume for the domain name */
1111 if ( lp_server_role() == ROLE_DOMAIN_MEMBER
) {
1112 if ( !strequal(lp_workgroup(), domain
) )
1115 if ( lp_winbind_use_default_domain() )
1119 /* only left with a domain controller */
1121 if ( strequal(get_global_sam_name(), domain
) ) {
1128 /* Parse a string of the form DOMAIN\user into a domain and a user */
1130 bool parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
1132 char *p
= strchr(domuser
,*lp_winbind_separator());
1135 fstrcpy(user
, domuser
);
1136 p
= strchr(domuser
, '@');
1138 if ( assume_domain(lp_workgroup()) && p
== NULL
) {
1139 fstrcpy(domain
, lp_workgroup());
1140 } else if (p
!= NULL
) {
1141 fstrcpy(domain
, p
+ 1);
1142 user
[PTR_DIFF(p
, domuser
)] = 0;
1148 fstrcpy(domain
, domuser
);
1149 domain
[PTR_DIFF(p
, domuser
)] = 0;
1152 return strupper_m(domain
);
1155 bool parse_domain_user_talloc(TALLOC_CTX
*mem_ctx
, const char *domuser
,
1156 char **domain
, char **user
)
1158 fstring fstr_domain
, fstr_user
;
1159 if (!parse_domain_user(domuser
, fstr_domain
, fstr_user
)) {
1162 *domain
= talloc_strdup(mem_ctx
, fstr_domain
);
1163 *user
= talloc_strdup(mem_ctx
, fstr_user
);
1164 return ((*domain
!= NULL
) && (*user
!= NULL
));
1167 /* Ensure an incoming username from NSS is fully qualified. Replace the
1168 incoming fstring with DOMAIN <separator> user. Returns the same
1169 values as parse_domain_user() but also replaces the incoming username.
1170 Used to ensure all names are fully qualified within winbindd.
1171 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1172 The protocol definitions of auth_crap, chng_pswd_auth_crap
1173 really should be changed to use this instead of doing things
1176 bool canonicalize_username(fstring username_inout
, fstring domain
, fstring user
)
1178 if (!parse_domain_user(username_inout
, domain
, user
)) {
1181 slprintf(username_inout
, sizeof(fstring
) - 1, "%s%c%s",
1182 domain
, *lp_winbind_separator(),
1188 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1189 'winbind separator' options.
1191 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1194 If we are a PDC or BDC, and this is for our domain, do likewise.
1196 On an AD DC we always fill DOMAIN\\USERNAME.
1198 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1200 void fill_domain_username(fstring name
, const char *domain
, const char *user
, bool can_assume
)
1204 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
) {
1208 fstrcpy(tmp_user
, user
);
1209 (void)strlower_m(tmp_user
);
1211 if (can_assume
&& assume_domain(domain
)) {
1212 strlcpy(name
, tmp_user
, sizeof(fstring
));
1214 slprintf(name
, sizeof(fstring
) - 1, "%s%c%s",
1215 domain
, *lp_winbind_separator(),
1221 * talloc version of fill_domain_username()
1222 * return NULL on talloc failure.
1224 char *fill_domain_username_talloc(TALLOC_CTX
*mem_ctx
,
1229 char *tmp_user
, *name
;
1231 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
) {
1235 tmp_user
= talloc_strdup(mem_ctx
, user
);
1236 if (!strlower_m(tmp_user
)) {
1237 TALLOC_FREE(tmp_user
);
1241 if (can_assume
&& assume_domain(domain
)) {
1244 name
= talloc_asprintf(mem_ctx
, "%s%c%s",
1246 *lp_winbind_separator(),
1248 TALLOC_FREE(tmp_user
);
1255 * Client list accessor functions
1258 static struct winbindd_cli_state
*_client_list
;
1259 static int _num_clients
;
1261 /* Return list of all connected clients */
1263 struct winbindd_cli_state
*winbindd_client_list(void)
1265 return _client_list
;
1268 /* Return list-tail of all connected clients */
1270 struct winbindd_cli_state
*winbindd_client_list_tail(void)
1272 return DLIST_TAIL(_client_list
);
1275 /* Return previous (read:newer) client in list */
1277 struct winbindd_cli_state
*
1278 winbindd_client_list_prev(struct winbindd_cli_state
*cli
)
1280 return DLIST_PREV(cli
);
1283 /* Add a connection to the list */
1285 void winbindd_add_client(struct winbindd_cli_state
*cli
)
1287 cli
->last_access
= time(NULL
);
1288 DLIST_ADD(_client_list
, cli
);
1292 /* Remove a client from the list */
1294 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
1296 DLIST_REMOVE(_client_list
, cli
);
1300 /* Move a client to head or list */
1302 void winbindd_promote_client(struct winbindd_cli_state
*cli
)
1304 cli
->last_access
= time(NULL
);
1305 DLIST_PROMOTE(_client_list
, cli
);
1308 /* Return number of open clients */
1310 int winbindd_num_clients(void)
1312 return _num_clients
;
1315 NTSTATUS
lookup_usergroups_cached(TALLOC_CTX
*mem_ctx
,
1316 const struct dom_sid
*user_sid
,
1317 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
1319 struct netr_SamInfo3
*info3
= NULL
;
1320 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1321 uint32_t num_groups
= 0;
1323 DEBUG(3,(": lookup_usergroups_cached\n"));
1328 info3
= netsamlogon_cache_get(mem_ctx
, user_sid
);
1330 if (info3
== NULL
) {
1331 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1335 * Before bug #7843 the "Domain Local" groups were added with a
1336 * lookupuseraliases call, but this isn't done anymore for our domain
1337 * so we need to resolve resource groups here.
1339 * When to use Resource Groups:
1340 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1342 status
= sid_array_from_info3(mem_ctx
, info3
,
1347 if (!NT_STATUS_IS_OK(status
)) {
1353 *p_num_groups
= num_groups
;
1354 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1356 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1361 /*********************************************************************
1362 We use this to remove spaces from user and group names
1363 ********************************************************************/
1365 NTSTATUS
normalize_name_map(TALLOC_CTX
*mem_ctx
,
1366 const char *domain_name
,
1370 struct winbindd_domain
*domain
= NULL
;
1373 if (!name
|| !normalized
) {
1374 return NT_STATUS_INVALID_PARAMETER
;
1377 if (!lp_winbind_normalize_names()) {
1378 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1381 domain
= find_domain_from_name_noinit(domain_name
);
1382 if (domain
== NULL
) {
1383 DBG_ERR("Failed to find domain '%s'\n", domain_name
);
1384 return NT_STATUS_NO_SUCH_DOMAIN
;
1387 /* Alias support and whitespace replacement are mutually
1390 nt_status
= resolve_username_to_alias(mem_ctx
, domain
,
1392 if (NT_STATUS_IS_OK(nt_status
)) {
1393 /* special return code to let the caller know we
1394 mapped to an alias */
1395 return NT_STATUS_FILE_RENAMED
;
1398 /* check for an unreachable domain */
1400 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1401 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1403 set_domain_offline(domain
);
1407 /* deal with whitespace */
1409 *normalized
= talloc_strdup(mem_ctx
, name
);
1410 if (!(*normalized
)) {
1411 return NT_STATUS_NO_MEMORY
;
1414 all_string_sub( *normalized
, " ", "_", 0 );
1416 return NT_STATUS_OK
;
1419 /*********************************************************************
1420 We use this to do the inverse of normalize_name_map()
1421 ********************************************************************/
1423 NTSTATUS
normalize_name_unmap(TALLOC_CTX
*mem_ctx
,
1428 struct winbindd_domain
*domain
= find_our_domain();
1430 if (!name
|| !normalized
) {
1431 return NT_STATUS_INVALID_PARAMETER
;
1434 if (!lp_winbind_normalize_names()) {
1435 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1438 /* Alias support and whitespace replacement are mutally
1441 /* When mapping from an alias to a username, we don't know the
1442 domain. But we only need a domain structure to cache
1443 a successful lookup , so just our own domain structure for
1446 nt_status
= resolve_alias_to_username(mem_ctx
, domain
,
1448 if (NT_STATUS_IS_OK(nt_status
)) {
1449 /* Special return code to let the caller know we mapped
1451 return NT_STATUS_FILE_RENAMED
;
1454 /* check for an unreachable domain */
1456 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1457 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1459 set_domain_offline(domain
);
1463 /* deal with whitespace */
1465 *normalized
= talloc_strdup(mem_ctx
, name
);
1466 if (!(*normalized
)) {
1467 return NT_STATUS_NO_MEMORY
;
1470 all_string_sub(*normalized
, "_", " ", 0);
1472 return NT_STATUS_OK
;
1475 /*********************************************************************
1476 ********************************************************************/
1478 bool winbindd_can_contact_domain(struct winbindd_domain
*domain
)
1480 struct winbindd_tdc_domain
*tdc
= NULL
;
1481 TALLOC_CTX
*frame
= talloc_stackframe();
1484 /* We can contact the domain if it is our primary domain */
1486 if (domain
->primary
) {
1491 /* Trust the TDC cache and not the winbindd_domain flags */
1493 if ((tdc
= wcache_tdc_fetch_domain(frame
, domain
->name
)) == NULL
) {
1494 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1500 /* Can always contact a domain that is in out forest */
1502 if (tdc
->trust_flags
& NETR_TRUST_FLAG_IN_FOREST
) {
1508 * On a _member_ server, we cannot contact the domain if it
1509 * is running AD and we have no inbound trust.
1513 domain
->active_directory
&&
1514 ((tdc
->trust_flags
& NETR_TRUST_FLAG_INBOUND
) != NETR_TRUST_FLAG_INBOUND
))
1516 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1517 "and we have no inbound trust.\n", domain
->name
));
1521 /* Assume everything else is ok (probably not true but what
1527 talloc_destroy(frame
);
1532 /*********************************************************************
1533 ********************************************************************/
1535 bool winbindd_internal_child(struct winbindd_child
*child
)
1537 if ((child
== idmap_child()) || (child
== locator_child())) {
1544 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1546 /*********************************************************************
1547 ********************************************************************/
1549 static void winbindd_set_locator_kdc_env(const struct winbindd_domain
*domain
)
1552 char addr
[INET6_ADDRSTRLEN
];
1553 const char *kdc
= NULL
;
1556 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1560 if (domain
->initialized
&& !domain
->active_directory
) {
1561 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s not AD\n",
1566 print_sockaddr(addr
, sizeof(addr
), &domain
->dcaddr
);
1569 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1571 kdc
= domain
->dcname
;
1574 if (!kdc
|| !*kdc
) {
1575 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1580 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1581 domain
->alt_name
) == -1) {
1585 DEBUG(lvl
,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1588 setenv(var
, kdc
, 1);
1592 /*********************************************************************
1593 ********************************************************************/
1595 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1597 struct winbindd_domain
*our_dom
= find_our_domain();
1599 winbindd_set_locator_kdc_env(domain
);
1601 if (domain
!= our_dom
) {
1602 winbindd_set_locator_kdc_env(our_dom
);
1606 /*********************************************************************
1607 ********************************************************************/
1609 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1613 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1617 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1618 domain
->alt_name
) == -1) {
1627 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1632 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1637 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1639 void set_auth_errors(struct winbindd_response
*resp
, NTSTATUS result
)
1641 resp
->data
.auth
.nt_status
= NT_STATUS_V(result
);
1642 fstrcpy(resp
->data
.auth
.nt_status_string
, nt_errstr(result
));
1644 /* we might have given a more useful error above */
1645 if (*resp
->data
.auth
.error_string
== '\0')
1646 fstrcpy(resp
->data
.auth
.error_string
,
1647 get_friendly_nt_error_msg(result
));
1648 resp
->data
.auth
.pam_error
= nt_status_to_pam(result
);
1651 bool is_domain_offline(const struct winbindd_domain
*domain
)
1653 if (get_global_winbindd_state_offline()) {
1656 return !domain
->online
;
1659 bool is_domain_online(const struct winbindd_domain
*domain
)
1661 return !is_domain_offline(domain
);
1665 * Parse an char array into a list of sids.
1667 * The input sidstr should consist of 0-terminated strings
1668 * representing sids, separated by newline characters '\n'.
1669 * The list is terminated by an empty string, i.e.
1670 * character '\0' directly following a character '\n'
1671 * (or '\0' right at the start of sidstr).
1673 bool parse_sidlist(TALLOC_CTX
*mem_ctx
, const char *sidstr
,
1674 struct dom_sid
**sids
, uint32_t *num_sids
)
1682 while (p
[0] != '\0') {
1684 const char *q
= NULL
;
1686 if (!dom_sid_parse_endp(p
, &sid
, &q
)) {
1687 DEBUG(1, ("Could not parse sid %s\n", p
));
1691 DEBUG(1, ("Got invalid sidstr: %s\n", p
));
1694 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx
, &sid
, sids
,
1704 bool parse_xidlist(TALLOC_CTX
*mem_ctx
, const char *xidstr
,
1705 struct unixid
**pxids
, uint32_t *pnum_xids
)
1708 struct unixid
*xids
= NULL
;
1709 uint32_t num_xids
= 0;
1716 while (p
[0] != '\0') {
1719 unsigned long long id
;
1724 xid
= (struct unixid
) { .type
= ID_TYPE_UID
};
1727 xid
= (struct unixid
) { .type
= ID_TYPE_GID
};
1735 id
= strtoull(p
, &endp
, 10);
1736 if ((id
== ULLONG_MAX
) && (errno
== ERANGE
)) {
1739 if (*endp
!= '\n') {
1745 if ((unsigned long long)xid
.id
!= id
) {
1749 tmp
= talloc_realloc(mem_ctx
, xids
, struct unixid
, num_xids
+1);
1755 xids
[num_xids
] = xid
;
1760 *pnum_xids
= num_xids
;