diff options
author | Gerald Carter <jerry@samba.org> | 2007-05-06 18:39:31 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:21:47 -0500 |
commit | 4b7123bba7181070a13280f8dd99b256ae4b4679 (patch) | |
tree | 75073c270c6fe1f6cf0e3c41c97a59bfadad5d78 | |
parent | bf7008abb8c79c0d4c86d60408b03e419a1dc0dc (diff) | |
download | samba-4b7123bba7181070a13280f8dd99b256ae4b4679.tar.gz samba-4b7123bba7181070a13280f8dd99b256ae4b4679.tar.bz2 samba-4b7123bba7181070a13280f8dd99b256ae4b4679.zip |
r22700: Add a simple wcache TRUSTDOM api for maintaing a complete
list of trusted domains without requiring each winbindd process
to aquire this on its own. This is needed for various idmap
plugins and for dealing with different trust topoligies.
list_trusted_domain() patches coming next.
(This used to be commit 2da62a3d965a9701e16e644fd6bc728b43f28489)
-rw-r--r-- | source3/nsswitch/winbindd.h | 15 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 464 |
2 files changed, 478 insertions, 1 deletions
diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 198c655b2d..f5e1c71317 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -157,6 +157,9 @@ struct winbindd_domain { fstring alt_name; /* alt Domain name (if any) */ fstring forest_name; /* Name of the AD forest we're in */ DOM_SID sid; /* SID for this domain */ + uint32 domain_flags; /* Domain flags from rpc_ds.h */ + uint32 domain_type; /* Domain type from rpc_ds.h */ + uint32 domain_trust_attribs; /* Trust attribs from rpc_ds.h */ BOOL initialized; /* Did we already ask for the domain mode? */ BOOL native_mode; /* is this a win2k domain in native mode ? */ BOOL active_directory; /* is this a win2k active directory ? */ @@ -332,6 +335,18 @@ struct winbindd_idmap_methods { void (*status)(void); }; +/* Data structures for dealing with the trusted domain cache */ + +struct winbindd_tdc_domain { + const char *domain_name; + const char *dns_name; + DOM_SID sid; + uint32 trust_flags; + uint32 trust_attribs; + uint32 trust_type; +}; + + #include "nsswitch/winbindd_proto.h" #define WINBINDD_ESTABLISH_LOOP 30 diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index 86e57cb07c..727c5c74df 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -4,7 +4,7 @@ Winbind cache backend functions Copyright (C) Andrew Tridgell 2001 - Copyright (C) Gerald Carter 2003 + Copyright (C) Gerald Carter 2003-2007 Copyright (C) Volker Lendecke 2005 Copyright (C) Guenther Deschner 2005 @@ -3328,6 +3328,468 @@ int winbindd_validate_cache(void) return ret; } +/********************************************************************* + ********************************************************************/ + +static BOOL add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom, + struct winbindd_tdc_domain **domains, + size_t *num_domains ) +{ + struct winbindd_tdc_domain *list = NULL; + size_t idx; + int i; + BOOL set_only = False; + + /* don't allow duplicates */ + + idx = *num_domains; + list = *domains; + + for ( i=0; i< (*num_domains); i++ ) { + if ( strequal( new_dom->name, list[i].domain_name ) ) { + DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n", + new_dom->name)); + idx = i; + set_only = True; + + break; + } + } + + if ( !set_only ) { + if ( !*domains ) { + list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 ); + idx = 0; + } else { + list = TALLOC_REALLOC_ARRAY( *domains, *domains, + struct winbindd_tdc_domain, + (*num_domains)+1); + idx = *num_domains; + } + + ZERO_STRUCT( list[idx] ); + } + + if ( !list ) + return False; + + list[idx].domain_name = talloc_strdup( list, new_dom->name ); + list[idx].dns_name = talloc_strdup( list, new_dom->alt_name ); + + if ( !is_null_sid( &new_dom->sid ) ) + sid_copy( &list[idx].sid, &new_dom->sid ); + + if ( new_dom->domain_flags != 0x0 ) + list[idx].trust_flags = new_dom->domain_flags; + + if ( new_dom->domain_type != 0x0 ) + list[idx].trust_type = new_dom->domain_type; + + if ( new_dom->domain_trust_attribs != 0x0 ) + list[idx].trust_attribs = new_dom->domain_trust_attribs; + + if ( !set_only ) { + *domains = list; + *num_domains = idx + 1; + } + + return True; +} + +/********************************************************************* + ********************************************************************/ + +static TDB_DATA make_tdc_key( const char *domain_name ) +{ + char *keystr = NULL; + TDB_DATA key = { NULL, 0 }; + + if ( !domain_name ) { + DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n")); + return key; + } + + + asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ); + key.dptr = (unsigned char*)keystr; + key.dsize = strlen_m(keystr) + 1; + + return key; +} + +/********************************************************************* + ********************************************************************/ + +static int pack_tdc_domains( struct winbindd_tdc_domain *domains, + size_t num_domains, + unsigned char **buf ) +{ + unsigned char *buffer = NULL; + int len = 0; + int buflen = 0; + int i = 0; + + DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n", + (int)num_domains)); + + buflen = 0; + + again: + len = 0; + + /* Store the number of array items first */ + len += tdb_pack( buffer+len, buflen-len, "d", + num_domains ); + + /* now pack each domain trust record */ + for ( i=0; i<num_domains; i++ ) { + + if ( buflen > 0 ) { + DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n", + domains[i].domain_name, + domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" )); + } + + len += tdb_pack( buffer+len, buflen-len, "fffddd", + domains[i].domain_name, + domains[i].dns_name, + sid_string_static(&domains[i].sid), + domains[i].trust_flags, + domains[i].trust_attribs, + domains[i].trust_type ); + } + + if ( buflen < len ) { + if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) { + DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n")); + buflen = -1; + goto done; + } + buflen = len; + goto again; + } + + *buf = buffer; + + done: + return buflen; +} + +/********************************************************************* + ********************************************************************/ + +static size_t unpack_tdc_domains( unsigned char *buf, int buflen, + struct winbindd_tdc_domain **domains ) +{ + fstring domain_name, dns_name, sid_string; + uint32 type, attribs, flags; + int num_domains; + int len = 0; + int i; + struct winbindd_tdc_domain *list = NULL; + + /* get the number of domains */ + len += tdb_unpack( buf+len, buflen-len, "d", &num_domains); + if ( len == -1 ) { + DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n")); + return 0; + } + + list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains ); + if ( !list ) { + DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n")); + return 0; + } + + for ( i=0; i<num_domains; i++ ) { + len += tdb_unpack( buf+len, buflen-len, "fffddd", + domain_name, + dns_name, + sid_string, + &flags, + &attribs, + &type ); + + if ( len == -1 ) { + DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n")); + TALLOC_FREE( list ); + return 0; + } + + DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) " + "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n", + domain_name, dns_name, sid_string, + flags, attribs, type)); + + list[i].domain_name = talloc_strdup( list, domain_name ); + list[i].dns_name = talloc_strdup( list, dns_name ); + if ( !string_to_sid( &(list[i].sid), sid_string ) ) { + DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n", + domain_name)); + } + list[i].trust_flags = flags; + list[i].trust_attribs = attribs; + list[i].trust_type = type; + } + + *domains = list; + + return num_domains; +} + +/********************************************************************* + ********************************************************************/ + +static BOOL wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains ) +{ + TDB_DATA key = make_tdc_key( lp_workgroup() ); + TDB_DATA data = { NULL, 0 }; + int ret; + + if ( !key.dptr ) + return False; + + /* See if we were asked to delete the cache entry */ + + if ( !domains ) { + ret = tdb_delete( wcache->tdb, key ); + goto done; + } + + data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr ); + + if ( !data.dptr ) { + ret = -1; + goto done; + } + + ret = tdb_store( wcache->tdb, key, data, 0 ); + + done: + SAFE_FREE( data.dptr ); + SAFE_FREE( key.dptr ); + + return ( ret != -1 ); +} + +/********************************************************************* + ********************************************************************/ + +BOOL wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains ) +{ + TDB_DATA key = make_tdc_key( lp_workgroup() ); + TDB_DATA data = { NULL, 0 }; + + *domains = NULL; + *num_domains = 0; + + if ( !key.dptr ) + return False; + + data = tdb_fetch( wcache->tdb, key ); + + SAFE_FREE( key.dptr ); + + if ( !data.dptr ) + return False; + + *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains ); + + SAFE_FREE( data.dptr ); + + if ( !*domains ) + return False; + + return True; +} + +/********************************************************************* + ********************************************************************/ + +BOOL wcache_tdc_add_domain( struct winbindd_domain *domain ) +{ + struct winbindd_tdc_domain *dom_list = NULL; + size_t num_domains = 0; + BOOL ret = False; + + DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, " + "flags = 0x%x, attributes = 0x%x, type = 0x%x\n", + domain->name, domain->alt_name, + sid_string_static(&domain->sid), + domain->domain_flags, + domain->domain_trust_attribs, + domain->domain_type)); + + if ( !init_wcache() ) { + return False; + } + + /* fetch the list */ + + wcache_tdc_fetch_list( &dom_list, &num_domains ); + + /* add the new domain */ + + if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) { + goto done; + } + + /* pack the domain */ + + if ( !wcache_tdc_store_list( dom_list, num_domains ) ) { + goto done; + } + + /* Success */ + + ret = True; + done: + TALLOC_FREE( dom_list ); + + return ret; +} + +/********************************************************************* + ********************************************************************/ + +struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name ) +{ + struct winbindd_tdc_domain *dom_list = NULL; + size_t num_domains = 0; + int i; + struct winbindd_tdc_domain *d = NULL; + + DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name)); + + if ( !init_wcache() ) { + return False; + } + + /* fetch the list */ + + wcache_tdc_fetch_list( &dom_list, &num_domains ); + + for ( i=0; i<num_domains; i++ ) { + if ( strequal(name, dom_list[i].domain_name) || + strequal(name, dom_list[i].dns_name) ) + { + DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n", + name)); + + d = TALLOC_P( ctx, struct winbindd_tdc_domain ); + if ( !d ) + break; + + d->domain_name = talloc_strdup( d, dom_list[i].domain_name ); + d->dns_name = talloc_strdup( d, dom_list[i].dns_name ); + sid_copy( &d->sid, &dom_list[i].sid ); + d->trust_flags = dom_list[i].trust_flags; + d->trust_type = dom_list[i].trust_type; + d->trust_attribs = dom_list[i].trust_attribs; + + break; + } + } + + TALLOC_FREE( dom_list ); + + return d; +} + + +/********************************************************************* + ********************************************************************/ + +void wcache_tdc_clear( void ) +{ + if ( !init_wcache() ) + return; + + wcache_tdc_store_list( NULL, 0 ); + + return; +} + + +/********************************************************************* + ********************************************************************/ + +static void wcache_save_user_pwinfo(struct winbindd_domain *domain, + NTSTATUS status, + const DOM_SID *user_sid, + const char *homedir, + const char *shell, + const char *gecos, + uint32 gid) +{ + struct cache_entry *centry; + + if ( (centry = centry_start(domain, status)) == NULL ) + return; + + centry_put_string( centry, homedir ); + centry_put_string( centry, shell ); + centry_put_string( centry, gecos ); + centry_put_uint32( centry, gid ); + + centry_end(centry, "NSS/PWINFO/%s", sid_string_static(user_sid) ); + + DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_static(user_sid) )); + + centry_free(centry); +} + +NTSTATUS nss_get_info_cached( struct winbindd_domain *domain, + const DOM_SID *user_sid, + TALLOC_CTX *ctx, + ADS_STRUCT *ads, LDAPMessage *msg, + char **homedir, char **shell, char **gecos, + gid_t *p_gid) +{ + struct winbind_cache *cache = get_cache(domain); + struct cache_entry *centry = NULL; + NTSTATUS nt_status; + + if (!cache->tdb) + goto do_query; + + centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s", sid_string_static(user_sid)); + + if (!centry) + goto do_query; + + *homedir = centry_string( centry, ctx ); + *shell = centry_string( centry, ctx ); + *gecos = centry_string( centry, ctx ); + *p_gid = centry_uint32( centry ); + + centry_free(centry); + + DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n", + sid_string_static(user_sid))); + + return NT_STATUS_OK; + +do_query: + + nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg, + homedir, shell, gecos, p_gid ); + + if ( NT_STATUS_IS_OK(nt_status) ) { + wcache_save_user_pwinfo( domain, nt_status, user_sid, + *homedir, *shell, *gecos, *p_gid ); + } + + if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) { + DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n", + domain->name )); + set_domain_offline( domain ); + } + + return nt_status; +} + + /* the cache backend methods are exposed via this structure */ struct winbindd_methods cache_methods = { True, |