summaryrefslogtreecommitdiff
path: root/source3/nsswitch/winbindd_cache.c
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2007-05-06 18:39:31 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:21:47 -0500
commit4b7123bba7181070a13280f8dd99b256ae4b4679 (patch)
tree75073c270c6fe1f6cf0e3c41c97a59bfadad5d78 /source3/nsswitch/winbindd_cache.c
parentbf7008abb8c79c0d4c86d60408b03e419a1dc0dc (diff)
downloadsamba-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)
Diffstat (limited to 'source3/nsswitch/winbindd_cache.c')
-rw-r--r--source3/nsswitch/winbindd_cache.c464
1 files changed, 463 insertions, 1 deletions
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,