summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/rpc_ds.h26
-rw-r--r--source3/nsswitch/winbindd.c4
-rw-r--r--source3/nsswitch/winbindd.h2
-rw-r--r--source3/nsswitch/winbindd_ads.c82
-rw-r--r--source3/nsswitch/winbindd_misc.c33
-rw-r--r--source3/nsswitch/winbindd_util.c219
6 files changed, 339 insertions, 27 deletions
diff --git a/source3/include/rpc_ds.h b/source3/include/rpc_ds.h
index 4ca49871f6..05258fb306 100644
--- a/source3/include/rpc_ds.h
+++ b/source3/include/rpc_ds.h
@@ -30,7 +30,6 @@
#define DS_ENUM_DOM_TRUSTS 0x28
-
/* macros for RPC's */
/* DSROLE_PRIMARY_DOMAIN_INFO_BASIC */
@@ -56,8 +55,6 @@
#define DS_DOMAIN_FUCNTION_2003_MIXED 1
#define DS_DOMAIN_FUNCTION_2003 2
-
-
typedef struct
{
uint16 machine_role;
@@ -81,7 +78,6 @@ typedef struct
#define DsRolePrimaryDomainInfoBasic 1
-
/* DS_Q_GETPRIMDOMINFO - DsGetPrimaryDomainInformation() request */
typedef struct
{
@@ -139,15 +135,33 @@ typedef struct {
} DS_DOMAIN_TRUSTS_CTR;
+/* Trust flags */
+
#define DS_DOMAIN_IN_FOREST 0x0001 /* domains in the forest to which
we belong; even different domain trees */
#define DS_DOMAIN_DIRECT_OUTBOUND 0x0002 /* trusted domains */
-#define DS_DOMAIN_TREE_ROOT 0x0004 /* root of our forest; also available in
- DsRoleGetPrimaryDomainInfo() */
+#define DS_DOMAIN_TREE_ROOT 0x0004 /* root of a forest */
#define DS_DOMAIN_PRIMARY 0x0008 /* our domain */
#define DS_DOMAIN_NATIVE_MODE 0x0010 /* native mode AD servers */
#define DS_DOMAIN_DIRECT_INBOUND 0x0020 /* trusting domains */
+/* Trust types */
+
+#define DS_DOMAIN_TRUST_TYPE_DOWNLEVEL 0x00000001
+#define DS_DOMAIN_TRUST_TYPE_UPLEVEL 0x00000002
+
+/* Trust attributes */
+
+#define DS_DOMAIN_TRUST_ATTRIB_NON_TRANSITIVE 0x00000001
+#define DS_DOMAIN_TRUST_ATTRIB_UPLEVEL_ONLY 0x00000002
+#define DS_DOMAIN_TRUST_ATTRIB_QUARANTINED_DOMAIN 0x00000004
+#define DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE 0x00000008
+#define DS_DOMAIN_TRUST_ATTRIB_CROSS_ORG 0x00000010
+#define DS_DOMAIN_TRUST_ATTRIB_IN_FOREST 0x00000020
+#define DS_DOMAIN_TRUST_ATTRIB_EXTERNAL 0x00000040
+
+
+
/* DS_Q_ENUM_DOM_TRUSTS - DsEnumerateDomainTrusts() request */
typedef struct
{
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index ed4a23681b..9c5cd3b0e3 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -1139,6 +1139,10 @@ int main(int argc, char **argv, char **envp)
netsamlogon_cache_init(); /* Non-critical */
+ /* clear the cached list of trusted domains */
+
+ wcache_tdc_clear();
+
if (!init_domain_list()) {
DEBUG(0,("unable to initalize domain list\n"));
exit(1);
diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h
index f5e1c71317..b316e988b8 100644
--- a/source3/nsswitch/winbindd.h
+++ b/source3/nsswitch/winbindd.h
@@ -350,7 +350,7 @@ struct winbindd_tdc_domain {
#include "nsswitch/winbindd_proto.h"
#define WINBINDD_ESTABLISH_LOOP 30
-#define WINBINDD_RESCAN_FREQ 300
+#define WINBINDD_RESCAN_FREQ lp_winbind_cache_time()
#define WINBINDD_PAM_AUTH_KRB5_RENEW_TIME 2592000 /* one month */
#define DOM_SEQUENCE_NONE ((uint32)-1)
diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c
index 355a093855..111736244a 100644
--- a/source3/nsswitch/winbindd_ads.c
+++ b/source3/nsswitch/winbindd_ads.c
@@ -1020,8 +1020,10 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
struct ds_domain_trust *domains = NULL;
int count = 0;
int i;
- uint32 flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND;
+ uint32 flags;
struct rpc_pipe_client *cli;
+ uint32 fr_flags = (DS_DOMAIN_IN_FOREST | DS_DOMAIN_TREE_ROOT);
+ int ret_count;
DEBUG(3,("ads: trusted_domains\n"));
@@ -1030,6 +1032,20 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
*names = NULL;
*dom_sids = NULL;
+ /* If this is our primary domain or a root in our forest,
+ query for all trusts. If not, then just look for domain
+ trusts in the target forest */
+
+ if ( domain->primary ||
+ ((domain->domain_flags&fr_flags) == fr_flags) )
+ {
+ flags = DS_DOMAIN_DIRECT_OUTBOUND |
+ DS_DOMAIN_DIRECT_INBOUND |
+ DS_DOMAIN_IN_FOREST;
+ } else {
+ flags = DS_DOMAIN_IN_FOREST;
+ }
+
result = cm_connect_netlogon(domain, &cli);
if (!NT_STATUS_IS_OK(result)) {
@@ -1067,14 +1083,70 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
/* Copy across names and sids */
+
+ ret_count = 0;
for (i = 0; i < count; i++) {
- (*names)[i] = domains[i].netbios_domain;
- (*alt_names)[i] = domains[i].dns_domain;
+ struct winbindd_domain d;
+
+ /* drop external trusts if this is not our primary
+ domain. This means that the returned number of
+ domains may be less that the ones actually trusted
+ by the DC. */
+
+ if ( (domains[i].trust_attributes == DS_DOMAIN_TRUST_ATTRIB_QUARANTINED_DOMAIN) &&
+ !domain->primary )
+ {
+ DEBUG(10,("trusted_domains: Skipping external trusted domain "
+ "%s because it is outside of our primary domain\n",
+ domains[i].netbios_domain));
+ continue;
+ }
+
+ (*names)[ret_count] = domains[i].netbios_domain;
+ (*alt_names)[ret_count] = domains[i].dns_domain;
+ sid_copy(&(*dom_sids)[ret_count], &domains[i].sid);
+
+ /* add to the trusted domain cache */
+
+ fstrcpy( d.name, domains[i].netbios_domain );
+ fstrcpy( d.alt_name, domains[i].dns_domain );
+ sid_copy( &d.sid, &domains[i].sid );
+
+ /* This gets a little tricky. If we are
+ following a transitive forest trust, then
+ innerit the flags, type, and attrins from
+ the domain we queried to make sure we don't
+ record the view of the trust from the wrong
+ side. Always view it from the side of our
+ primary domain. --jerry */
+ if ( domain->primary ||
+ ((domain->domain_flags&fr_flags) == fr_flags) )
+ {
+ DEBUG(10,("trusted_domains(ads): Storing trust "
+ "flags for domain %s\n", d.alt_name));
+
+ /* Look this up in cache to make sure
+ we have the current trust flags and
+ attributes */
+
+ d.domain_flags = domains[i].flags;
+ d.domain_type = domains[i].trust_type;
+ d.domain_trust_attribs = domains[i].trust_attributes;
+ } else {
+ DEBUG(10,("trusted_domains(ads): Inheriting trust "
+ "flags for domain %s\n", d.alt_name));
+ d.domain_flags = domain->domain_flags;
+ d.domain_type = domain->domain_type;
+ d.domain_trust_attribs = domain->domain_trust_attribs;
+ }
+
+ wcache_tdc_add_domain( &d );
+
+ ret_count++;
- sid_copy(&(*dom_sids)[i], &domains[i].sid);
}
- *num_domains = count;
+ *num_domains = ret_count;
}
return result;
diff --git a/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c
index f5363cad1a..ac751bf2a8 100644
--- a/source3/nsswitch/winbindd_misc.c
+++ b/source3/nsswitch/winbindd_misc.c
@@ -100,10 +100,41 @@ enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *do
void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
{
+ struct winbindd_domain *d = NULL;
+ int extra_data_len = 0;
+ char *extra_data = NULL;
+
DEBUG(3, ("[%5lu]: list trusted domains\n",
(unsigned long)state->pid));
- sendto_domain(state, find_our_domain());
+ for ( d=domain_list(); d; d=d->next ) {
+ if ( !extra_data ) {
+ extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
+ d->name,
+ d->alt_name ? d->alt_name : d->name,
+ sid_string_static(&d->sid));
+ } else {
+ extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
+ extra_data,
+ d->name,
+ d->alt_name ? d->alt_name : d->name,
+ sid_string_static(&d->sid));
+ }
+ }
+
+ extra_data_len = 0;
+ if (extra_data != NULL) {
+ extra_data_len = strlen(extra_data);
+ }
+
+ if (extra_data_len > 0) {
+ state->response.extra_data.data = SMB_STRDUP(extra_data);
+ state->response.length += extra_data_len+1;
+ }
+
+ TALLOC_FREE( extra_data );
+
+ request_ok(state);
}
enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c
index 49d381913a..56de808c2d 100644
--- a/source3/nsswitch/winbindd_util.c
+++ b/source3/nsswitch/winbindd_util.c
@@ -112,24 +112,42 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
init_domain_list() and we'll get stuck in a loop. */
for (domain = _domain_list; domain; domain = domain->next) {
if (strequal(domain_name, domain->name) ||
- strequal(domain_name, domain->alt_name)) {
- return domain;
+ strequal(domain_name, domain->alt_name))
+ {
+ break;
}
- if (alternative_name && *alternative_name) {
+
+ if (alternative_name && *alternative_name)
+ {
if (strequal(alternative_name, domain->name) ||
- strequal(alternative_name, domain->alt_name)) {
- return domain;
+ strequal(alternative_name, domain->alt_name))
+ {
+ break;
}
}
- if (sid) {
+
+ if (sid)
+ {
if (is_null_sid(sid)) {
+ continue;
+ }
- } else if (sid_equal(sid, &domain->sid)) {
- return domain;
+ if (sid_equal(sid, &domain->sid)) {
+ break;
}
}
}
+ /* See if we found a match. Check if we need to update the
+ SID. */
+
+ if ( domain ) {
+ if ( sid_equal( &domain->sid, &global_sid_NULL ) )
+ sid_copy( &domain->sid, sid );
+
+ return domain;
+ }
+
/* Create new domain entry */
if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
@@ -165,6 +183,8 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
/* Link to domain list */
DLIST_ADD(_domain_list, domain);
+ wcache_tdc_add_domain( domain );
+
DEBUG(2,("Added domain %s %s %s\n",
domain->name, domain->alt_name,
&domain->sid?sid_string_static(&domain->sid):""));
@@ -178,16 +198,21 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
struct trustdom_state {
TALLOC_CTX *mem_ctx;
+ BOOL primary;
+ BOOL forest_root;
struct winbindd_response *response;
};
static void trustdom_recv(void *private_data, BOOL success);
+static void rescan_forest_root_trusts( void );
+static void rescan_forest_trusts( void );
static void add_trusted_domains( struct winbindd_domain *domain )
{
TALLOC_CTX *mem_ctx;
struct winbindd_request *request;
struct winbindd_response *response;
+ uint32 fr_flags = (DS_DOMAIN_TREE_ROOT|DS_DOMAIN_IN_FOREST);
struct trustdom_state *state;
@@ -210,6 +235,11 @@ static void add_trusted_domains( struct winbindd_domain *domain )
state->mem_ctx = mem_ctx;
state->response = response;
+ /* Flags used to know how to continue the forest trust search */
+
+ state->primary = domain->primary;
+ state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
+
request->length = sizeof(*request);
request->cmd = WINBINDD_LIST_TRUSTDOM;
@@ -235,6 +265,8 @@ static void trustdom_recv(void *private_data, BOOL success)
while ((p != NULL) && (*p != '\0')) {
char *q, *sidstr, *alt_name;
DOM_SID sid;
+ struct winbindd_domain *domain;
+ char *alternate_name = NULL;
alt_name = strchr(p, '\\');
if (alt_name == NULL) {
@@ -268,15 +300,21 @@ static void trustdom_recv(void *private_data, BOOL success)
}
}
- if (find_domain_from_name_noinit(p) == NULL) {
- struct winbindd_domain *domain;
- char *alternate_name = NULL;
-
/* use the real alt_name if we have one, else pass in NULL */
if ( !strequal( alt_name, "(null)" ) )
alternate_name = alt_name;
+ /* If we have an existing domain structure, calling
+ add_trusted_domain() will update the SID if
+ necessary. This is important because we need the
+ SID for sibling domains */
+
+ if ( find_domain_from_name_noinit(p) != NULL ) {
+ domain = add_trusted_domain(p, alternate_name,
+ &cache_methods,
+ &sid);
+ } else {
domain = add_trusted_domain(p, alternate_name,
&cache_methods,
&sid);
@@ -288,13 +326,161 @@ static void trustdom_recv(void *private_data, BOOL success)
}
SAFE_FREE(response->extra_data.data);
+
+ /*
+ Cases to consider when scanning trusts:
+ (a) we are calling from a child domain (primary && !forest_root)
+ (b) we are calling from the root of the forest (primary && forest_root)
+ (c) we are calling from a trusted forest domain (!primary
+ && !forest_root)
+ */
+
+ if ( state->primary ) {
+ /* If this is our primary domain and we are not the in the
+ forest root, we have to scan the root trusts first */
+
+ if ( !state->forest_root )
+ rescan_forest_root_trusts();
+ else
+ rescan_forest_trusts();
+
+ } else if ( state->forest_root ) {
+ /* Once we have done root forest trust search, we can
+ go on to search thing trusted forests */
+
+ rescan_forest_trusts();
+ }
+
talloc_destroy(state->mem_ctx);
+
+ return;
}
/********************************************************************
- Periodically we need to refresh the trusted domain cache for smbd
+ Scan the trusts of our forest root
********************************************************************/
+static void rescan_forest_root_trusts( void )
+{
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_trusts = 0;
+ int i;
+
+ /* The only transitive trusts supported by Windows 2003 AD are
+ (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
+ first two are handled in forest and listed by
+ DsEnumerateDomainTrusts(). Forest trusts are not so we
+ have to do that ourselves. */
+
+ if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
+ return;
+
+ for ( i=0; i<num_trusts; i++ ) {
+ struct winbindd_domain *d = NULL;
+
+ /* Find the forest root. Don't necessarily trust
+ the domain_list() as our primary domain may not
+ have been initialized. */
+
+ if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
+ continue;
+ }
+
+ /* Here's the forest root */
+
+ d = find_domain_from_name_noinit( dom_list[i].domain_name );
+
+ if ( !d ) {
+ d = add_trusted_domain( dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &cache_methods,
+ &dom_list[i].sid );
+ }
+
+ DEBUG(10,("rescan_forest_root_trusts: Following trust path "
+ "for domain tree root %s (%s)\n",
+ d->name, d->alt_name ));
+
+ d->domain_flags = dom_list[i].trust_flags;
+ d->domain_type = dom_list[i].trust_type;
+ d->domain_trust_attribs = dom_list[i].trust_attribs;
+
+ add_trusted_domains( d );
+
+ break;
+ }
+
+ TALLOC_FREE( dom_list );
+
+ return;
+}
+
+/********************************************************************
+ scan the transitive forest trists (not our own)
+********************************************************************/
+
+
+static void rescan_forest_trusts( void )
+{
+ struct winbindd_domain *d = NULL;
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_trusts = 0;
+ int i;
+
+ /* The only transitive trusts supported by Windows 2003 AD are
+ (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
+ first two are handled in forest and listed by
+ DsEnumerateDomainTrusts(). Forest trusts are not so we
+ have to do that ourselves. */
+
+ if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
+ return;
+
+ for ( i=0; i<num_trusts; i++ ) {
+ uint32 flags = dom_list[i].trust_flags;
+ uint32 type = dom_list[i].trust_type;
+ uint32 attribs = dom_list[i].trust_attribs;
+
+ d = find_domain_from_name_noinit( dom_list[i].domain_name );
+
+ /* ignore our primary and internal domains */
+
+ if ( d && (d->internal || d->primary ) )
+ continue;
+
+ if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
+ (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
+ (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
+ {
+ /* add the trusted domain if we don't know
+ about it */
+
+ if ( !d ) {
+ d = add_trusted_domain( dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &cache_methods,
+ &dom_list[i].sid );
+ }
+
+ DEBUG(10,("Following trust path for domain %s (%s)\n",
+ d->name, d->alt_name ));
+ add_trusted_domains( d );
+ }
+ }
+
+ TALLOC_FREE( dom_list );
+
+ return;
+}
+
+/*********************************************************************
+ The process of updating the trusted domain list is a three step
+ async process:
+ (a) ask our domain
+ (b) ask the root domain in our forest
+ (c) ask the a DC in any Win2003 trusted forests
+*********************************************************************/
+
void rescan_trusted_domains( void )
{
time_t now = time(NULL);
@@ -305,7 +491,12 @@ void rescan_trusted_domains( void )
((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
return;
- /* this will only add new domains we didn't already know about */
+ /* clear the TRUSTDOM cache first */
+
+ wcache_tdc_clear();
+
+ /* this will only add new domains we didn't already know about
+ in the domain_list()*/
add_trusted_domains( find_our_domain() );