diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/rpc_ds.h | 26 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.c | 4 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.h | 2 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_ads.c | 82 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_misc.c | 33 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_util.c | 219 |
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() ); |