Fix immediate bug where the idmap can't tell the difference between an entry
[ira/wip.git] / source3 / nsswitch / winbindd_util.c
index 41eb8b9d287d0ea550df6f9880e9be803ba18365..0bc4beeac6c272423eda097c989713d8659cdcec 100644 (file)
@@ -1,5 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
+   Unix SMB/CIFS implementation.
 
    Winbind daemon for ntdom nss module
 
@@ -22,7 +22,9 @@
 */
 
 #include "winbindd.h"
-#include "sids.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
 
 /**
  * @file winbindd_util.c
  *
  * Correct code should never look at a field that has this value.
  **/
-static const fstring name_deadbeef = "<deadbeef>";
-
 
-/* Globals for domain list stuff */
-struct winbindd_domain *domain_list = NULL;
+static const fstring name_deadbeef = "<deadbeef>";
 
-static struct winbindd_methods msrpc_methods = {
-       winbindd_query_dispinfo
-};
+/* The list of trusted domains.  Note that the list can be deleted and
+   recreated using the init_domain_list() function so pointers to
+   individual winbindd_domain structures cannot be made.  Keep a copy of
+   the domain name instead. */
 
-/* Given a domain name, return the struct winbindd domain info for it 
-   if it is actually working. */
+static struct winbindd_domain *_domain_list;
 
-struct winbindd_domain *find_domain_from_name(char *domain_name)
+struct winbindd_domain *domain_list(void)
 {
-       struct winbindd_domain *tmp;
-
-       if (domain_list == NULL)
-               get_domain_info();
-
-       /* Search through list */
-
-       for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
-               if (strcmp(domain_name, tmp->name) == 0)
-                       return tmp;
-       }
+       /* Initialise list */
 
-       /* Not found */
+       if (!_domain_list)
+               init_domain_list();
 
-       return NULL;
+       return _domain_list;
 }
 
-/* Given a domain name, return the struct winbindd domain info for it */
+/* Free all entries in the trusted domain list */
 
-struct winbindd_domain *find_domain_from_sid(DOM_SID *sid)
+void free_domain_list(void)
 {
-       struct winbindd_domain *tmp;
-
-       if (domain_list == NULL)
-               get_domain_info();
-
-       /* Search through list */
-
-       for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
-               if (sid_equal(sid, &tmp->sid))
-                       return tmp;
+       struct winbindd_domain *domain = _domain_list;
+
+       while(domain) {
+               struct winbindd_domain *next = domain->next;
+               
+               DLIST_REMOVE(_domain_list, domain);
+               SAFE_FREE(domain);
+               domain = next;
        }
-
-       /* Not found */
-
-       return NULL;
 }
 
-/* Add a trusted domain to our list of domains */
 
-static struct winbindd_domain *add_trusted_domain(char *domain_name,
-                                                  DOM_SID *domain_sid,
-                                                 struct winbindd_methods *methods)
+/* Add a trusted domain to our list of domains */
+static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
+                                                 struct winbindd_methods *methods,
+                                                 DOM_SID *sid)
 {
-       struct winbindd_domain *domain, *tmp;
+       struct winbindd_domain *domain;
         
-       for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
-               if (strcmp(domain_name, tmp->name) == 0) {
-                       DEBUG(3, ("domain %s already in domain list\n", domain_name));
-                       return tmp;
+       /* We can't call domain_list() as this function is called from
+          init_domain_list() and we'll get stuck in a loop. */
+       for (domain = _domain_list; domain; domain = domain->next) {
+               if (strcasecmp(domain_name, domain->name) == 0 ||
+                   strcasecmp(domain_name, domain->alt_name) == 0) {
+                       return domain;
+               }
+               if (alt_name && *alt_name) {
+                       if (strcasecmp(alt_name, domain->name) == 0 ||
+                           strcasecmp(alt_name, domain->alt_name) == 0) {
+                               return domain;
+                       }
                }
        }
         
-       DEBUG(1, ("adding domain %s\n", domain_name));
-        
        /* Create new domain entry */
-        
-       if ((domain = (struct winbindd_domain *)malloc(sizeof(*domain))) == NULL)
+
+       if ((domain = (struct winbindd_domain *)
+            malloc(sizeof(*domain))) == NULL)
                return NULL;
 
        /* Fill in fields */
         
        ZERO_STRUCTP(domain);
+
+       /* prioritise the short name */
+       if (strchr_m(domain_name, '.') && alt_name && *alt_name) {
+               fstrcpy(domain->name, alt_name);
+               fstrcpy(domain->alt_name, domain_name);
+       } else {
        fstrcpy(domain->name, domain_name);
-       sid_copy(&domain->sid, domain_sid);
-        domain->methods = methods;
+               if (alt_name) {
+                       fstrcpy(domain->alt_name, alt_name);
+               }
+       }
+
+       domain->methods = methods;
+       domain->backend = NULL;
+       domain->sequence_number = DOM_SEQUENCE_NONE;
+       domain->last_seq_check = 0;
+       if (sid) {
+               sid_copy(&domain->sid, sid);
+       }
+       
+       /* see if this is a native mode win2k domain */
+          
+       domain->native_mode = cm_check_for_native_mode_win2k( domain_name );
+       DEBUG(3,("add_trusted_domain: %s is a %s mode domain\n", domain_name,
+               domain->native_mode ? "native" : "mixed (or NT4)" ));
 
        /* Link to domain list */
+       DLIST_ADD(_domain_list, domain);
         
-       DLIST_ADD(domain_list, domain);
+       DEBUG(1,("Added domain %s %s %s\n", 
+                domain->name, domain->alt_name,
+                sid?sid_string_static(&domain->sid):""));
         
        return domain;
 }
 
-/* Look up global info for the winbind daemon */
 
-BOOL get_domain_info(void)
+/*
+  rescan our domains looking for new trusted domains
+ */
+void rescan_trusted_domains(BOOL force)
 {
-       uint32 enum_ctx = 0, num_doms = 0;
-       char **domains = NULL;
-       DOM_SID *sids = NULL, domain_sid;
-       NTSTATUS result;
-       CLI_POLICY_HND *hnd;
-       int i;
-       fstring level5_dom;
-       BOOL rv = False;
+       struct winbindd_domain *domain;
        TALLOC_CTX *mem_ctx;
-       
-       DEBUG(1, ("getting trusted domain list\n"));
-
-       if (!(mem_ctx = talloc_init()))
-               return False;
-
-       /* Add our workgroup - keep handle to look up trusted domains */
-
-       if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
-               goto done;
-
-       result = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
-                                       &hnd->pol, 0x05, level5_dom, &domain_sid);
-
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       add_trusted_domain(lp_workgroup(), &domain_sid, &msrpc_methods);
-       
-       /* Enumerate list of trusted domains */ 
-
-       if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
-               goto done;
-
-       result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
-                                               &hnd->pol, &enum_ctx, &num_doms, &domains, &sids);
-       
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
-       
-       /* Add each domain to the trusted domain list */
+       static time_t last_scan;
+       time_t t = time(NULL);
 
-       for(i = 0; i < num_doms; i++)
-               add_trusted_domain(domains[i], &sids[i], &msrpc_methods);
-
-       rv = True;      
-
- done:
-
-       talloc_destroy(mem_ctx);
+       /* trusted domains might be disabled */
+       if (!lp_allow_trusted_domains()) {
+               return;
+       }
 
-       return rv;
-}
+       /* Only rescan every few minutes but force if necessary */
 
-/* Free global domain info */
+       if (((unsigned)(t - last_scan) < WINBINDD_RESCAN_FREQ) && !force)
+               return;
 
-void free_domain_info(void)
-{
-       struct winbindd_domain *domain;
+       last_scan = t;
 
-       /* Free list of domains */
+       DEBUG(1, ("scanning trusted domain list\n"));
 
-       if (domain_list) {
-               struct winbindd_domain *next_domain;
+       if (!(mem_ctx = talloc_init("init_domain_list")))
+               return;
 
-               domain = domain_list;
+       for (domain = _domain_list; domain; domain = domain->next) {
+               NTSTATUS result;
+               char **names;
+               char **alt_names;
+               int num_domains = 0;
+               DOM_SID *dom_sids;
+               int i;
 
-               while(domain) {
-                       next_domain = domain->next;
-                       SAFE_FREE(domain);
-                       domain = next_domain;
+               result = domain->methods->trusted_domains(domain, mem_ctx, &num_domains,
+                                                         &names, &alt_names, &dom_sids);
+               if (!NT_STATUS_IS_OK(result)) {
+                       continue;
                }
-       }
-}
 
-/* Connect to a domain controller using get_any_dc_name() to discover 
-   the domain name and sid */
-
-BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
-{
-       fstring level5_dom;
-       uint32 enum_ctx = 0, num_doms = 0;
-       char **domains = NULL;
-       DOM_SID *sids = NULL;
-       CLI_POLICY_HND *hnd;
-       NTSTATUS result;
-       BOOL rv = False;
-       TALLOC_CTX *mem_ctx;
-        
-       DEBUG(1, ("looking up sid for domain %s\n", domain_name));
-        
-       if (!(mem_ctx = talloc_init()))
-               return False;
-        
-       if (!(hnd = cm_get_lsa_handle(domain_name)))
-               goto done;
-        
-       /* Do a level 5 query info policy if we are looking up the SID for
-               our own domain. */
-        
-       if (strequal(domain_name, lp_workgroup())) {
-                
-               result = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
-                                               &hnd->pol, 0x05, level5_dom,
-                                               &domain->sid);
-                
-                       rv = NT_STATUS_IS_OK(result);
-                       goto done;
-       } 
-        
-       /* Use lsaenumdomains to get sid for this domain */
-        
-       result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx, &hnd->pol,
-                                               &enum_ctx, &num_doms, &domains, &sids);
-        
-       /* Look for domain name */
-        
-       if (NT_STATUS_IS_OK(result) && domains && sids) {
-               BOOL found = False;
-               int i;
-                
-               for(i = 0; i < num_doms; i++) {
-                       if (strequal(domain_name, domains[i])) {
-                               sid_copy(&domain->sid, &sids[i]);
-                               found = True;
-                               break;
-                       }
+               /* Add each domain to the trusted domain list. Each domain inherits
+                  the access methods of its parent */
+               for(i = 0; i < num_domains; i++) {
+                       DEBUG(10,("Found domain %s\n", names[i]));
+                       add_trusted_domain(names[i], alt_names?alt_names[i]:NULL,
+                                          domain->methods, &dom_sids[i]);
+                       
+                       /* store trusted domain in the cache */
+                       trustdom_cache_store(names[i], alt_names ? alt_names[i] : NULL,
+                                            &dom_sids[i], t + WINBINDD_RESCAN_FREQ);
                }
-                
-               rv = found;
-               goto done;
        }
-      
-       rv = False;             /* An error occured with a trusted domain */
-
- done:
 
        talloc_destroy(mem_ctx);
-
-       return rv;
 }
 
-/* Store a SID in a domain indexed by name in the cache. */
-
-static void store_sid_by_name_in_cache(fstring name, DOM_SID *sid, enum SID_NAME_USE type)
-{
-       fstring domain_str;
-       char *p;
-       struct winbindd_sid sid_val;
-       struct winbindd_domain *domain;
-
-       /* Get name from domain. */
-       fstrcpy( domain_str, name);
-       p = strchr(domain_str, '\\');
-       if (p)
-               *p = '\0';
-
-       if ((domain = find_domain_from_name(domain_str)) == NULL)
-        return;
-
-       sid_to_string(sid_val.sid, sid);
-       sid_val.type = (int)type;
-
-       DEBUG(10,("store_sid_by_name_in_cache: storing cache entry %s -> SID %s\n",
-               name, sid_val.sid ));
-
-       winbindd_store_sid_cache_entry(domain, name, &sid_val);
-}
-
-/* Lookup a SID in a domain indexed by name in the cache. */
-
-static BOOL winbindd_lookup_sid_by_name_in_cache(fstring name, DOM_SID *sid, enum SID_NAME_USE *type)
+/* Look up global info for the winbind daemon */
+BOOL init_domain_list(void)
 {
-       fstring domain_str;
-       char *p;
-       struct winbindd_sid sid_ret;
+       extern struct winbindd_methods cache_methods;
        struct winbindd_domain *domain;
 
-       /* Get name from domain. */
-       fstrcpy( domain_str, name);
-       p = strchr(domain_str, '\\');
-       if (p)
-               *p = '\0';
+       /* Free existing list */
+       free_domain_list();
 
-       if ((domain = find_domain_from_name(domain_str)) == NULL)
-                return False;
-
-       if (!winbindd_fetch_sid_cache_entry(domain, name, &sid_ret))
+       /* Add ourselves as the first entry */
+       domain = add_trusted_domain(lp_workgroup(), NULL, &cache_methods, NULL);
+       if (!secrets_fetch_domain_sid(domain->name, &domain->sid)) {
+               DEBUG(1, ("Could not fetch sid for our domain %s\n",
+                         domain->name));
                return False;
+       }
 
-       string_to_sid( sid, sid_ret.sid);
-       *type = (enum SID_NAME_USE)sid_ret.type;
+       /* get any alternate name for the primary domain */
+       cache_methods.alternate_name(domain);
 
-       DEBUG(10,("winbindd_lookup_sid_by_name_in_cache: Cache hit for name %s. SID = %s\n",
-               name, sid_ret.sid ));
+       /* do an initial scan for trusted domains */
+       rescan_trusted_domains(True);
 
        return True;
 }
 
-/* Store a name in a domain indexed by SID in the cache. */
+/* Given a domain name, return the struct winbindd domain info for it 
+   if it is actually working. */
 
-static void store_name_by_sid_in_cache(DOM_SID *sid, fstring name, enum SID_NAME_USE type)
+struct winbindd_domain *find_domain_from_name(const char *domain_name)
 {
-       fstring sid_str;
-       uint32 rid;
-       DOM_SID domain_sid;
-       struct winbindd_name name_val;
        struct winbindd_domain *domain;
 
-       /* Split sid into domain sid and user rid */
-       sid_copy(&domain_sid, sid);
-       sid_split_rid(&domain_sid, &rid);
-
-       if ((domain = find_domain_from_sid(&domain_sid)) == NULL)
-        return;
+       /* Search through list */
 
-       sid_to_string(sid_str, sid);
-       fstrcpy( name_val.name, name );
-       name_val.type = (int)type;
+       for (domain = domain_list(); domain != NULL; domain = domain->next) {
+               if (strequal(domain_name, domain->name) ||
+                   (domain->alt_name[0] && strequal(domain_name, domain->alt_name)))
+                       return domain;
+       }
 
-       DEBUG(10,("store_name_by_sid_in_cache: storing cache entry SID %s -> %s\n",
-               sid_str, name_val.name ));
+       /* Not found */
 
-       winbindd_store_name_cache_entry(domain, sid_str, &name_val);
+       return NULL;
 }
 
-/* Lookup a name in a domain indexed by SID in the cache. */
+/* Given a domain sid, return the struct winbindd domain info for it */
 
-static BOOL winbindd_lookup_name_by_sid_in_cache(DOM_SID *sid, fstring name, enum SID_NAME_USE *type)
+struct winbindd_domain *find_domain_from_sid(DOM_SID *sid)
 {
-       fstring sid_str;
-       uint32 rid;
-       DOM_SID domain_sid;
-       struct winbindd_name name_ret;
        struct winbindd_domain *domain;
 
-       /* Split sid into domain sid and user rid */
-       sid_copy(&domain_sid, sid);
-       sid_split_rid(&domain_sid, &rid);
-
-       if ((domain = find_domain_from_sid(&domain_sid)) == NULL)
-                return False;
-
-       sid_to_string(sid_str, sid);
-
-       if (!winbindd_fetch_name_cache_entry(domain, sid_str, &name_ret))
-               return False;
+       /* Search through list */
 
-       fstrcpy( name, name_ret.name );
-       *type = (enum SID_NAME_USE)name_ret.type;
+       for (domain = domain_list(); domain != NULL; domain = domain->next) {
+               if (sid_compare_domain(sid, &domain->sid) == 0)
+                       return domain;
+       }
 
-       DEBUG(10,("winbindd_lookup_name_by_sid_in_cache: Cache hit for SID = %s, name %s\n",
-               sid_str, name ));
+       /* Not found */
 
-       return True;
+       return NULL;
 }
 
 /* Lookup a sid in a domain from a name */
 
-BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid, enum SID_NAME_USE *type)
+BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, 
+                                const char *name, DOM_SID *sid, 
+                                enum SID_NAME_USE *type)
 {
-       int num_sids = 0, num_names = 1;
-       DOM_SID *sids = NULL;
-       uint32 *types = NULL;
-       CLI_POLICY_HND *hnd;
        NTSTATUS result;
-       TALLOC_CTX *mem_ctx;
-       BOOL rv = False;
-        
+        TALLOC_CTX *mem_ctx;
        /* Don't bother with machine accounts */
-        
+
        if (name[strlen(name) - 1] == '$')
                return False;
 
-       /* First check cache. */
-       if (winbindd_lookup_sid_by_name_in_cache(name, sid, type)) {
-               if (*type == SID_NAME_USE_NONE)
-                       return False; /* Negative cache hit. */
-               return True;
-       }
-       /* Lookup name */
-        
-       if (!(mem_ctx = talloc_init()))
+       mem_ctx = talloc_init("lookup_sid_by_name for %s\n", name);
+       if (!mem_ctx) 
                return False;
         
-       if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
-               goto done;
-        
-       result = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 
-                               num_names, (char **)&name, &sids, 
-                               &types, &num_sids);
+       /* Lookup name */
+       result = domain->methods->name_to_sid(domain, mem_ctx, name, sid, type);
+
+       talloc_destroy(mem_ctx);
         
        /* Return rid and type if lookup successful */
-        
-       if (NT_STATUS_IS_OK(result)) {
-                
-               /* Return sid */
-                
-               if ((sid != NULL) && (sids != NULL))
-                       sid_copy(sid, &sids[0]);
-                
-               /* Return name type */
-                
-               if ((type != NULL) && (types != NULL))
-                       *type = types[0];
-
-               /* Store the forward and reverse map of this lookup in the cache. */
-                store_sid_by_name_in_cache(name, &sids[0], types[0]);
-               store_name_by_sid_in_cache(&sids[0], name, types[0]);
-       } else {
-               /* JRA. Here's where we add the -ve cache store with a name type of SID_NAME_USE_NONE. */
-               DOM_SID nullsid;
-
-               ZERO_STRUCT(nullsid);
-               store_sid_by_name_in_cache(name, &nullsid, SID_NAME_USE_NONE);
+       if (!NT_STATUS_IS_OK(result)) {
                *type = SID_NAME_UNKNOWN;
        }
 
-       rv = NT_STATUS_IS_OK(result);
-
- done:
-       talloc_destroy(mem_ctx);
-        
-       return rv;
+       return NT_STATUS_IS_OK(result);
 }
 
 /**
@@ -461,6 +300,8 @@ BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid, enum SID_NAME_USE *ty
  *
  * @param name On success, set to the name corresponding to @p sid.
  * 
+ * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
+ * 
  * @param type On success, contains the type of name: alias, group or
  * user.
  *
@@ -468,431 +309,476 @@ BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid, enum SID_NAME_USE *ty
  * are set, otherwise False.
  **/
 BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
+                                fstring dom_name,
                                 fstring name,
                                 enum SID_NAME_USE *type)
 {
-       int num_sids = 1, num_names = 0;
-       uint32 *types = NULL;
-       char **names;
-       CLI_POLICY_HND *hnd;
+       char *names;
        NTSTATUS result;
        TALLOC_CTX *mem_ctx;
        BOOL rv = False;
+       struct winbindd_domain *domain;
 
-       /* First check cache. */
-       if (winbindd_lookup_name_by_sid_in_cache(sid, name, type)) {
-               if (*type == SID_NAME_USE_NONE) {
-                       fstrcpy(name, name_deadbeef);
-                       *type = SID_NAME_UNKNOWN;
-                       return False; /* Negative cache hit. */
-               } else 
-                       return True;
+       domain = find_domain_from_sid(sid);
+
+       if (!domain) {
+               DEBUG(1,("Can't find domain from sid\n"));
+               return False;
        }
 
        /* Lookup name */
 
-       if (!(mem_ctx = talloc_init()))
+       if (!(mem_ctx = talloc_init("winbindd_lookup_name_by_sid")))
                return False;
         
-       if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
-               goto done;
-        
-       result = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
-                                                       num_sids, sid, &names, &types, 
-                                                       &num_names);
+       result = domain->methods->sid_to_name(domain, mem_ctx, sid, &names, type);
 
        /* Return name and type if successful */
         
        if ((rv = NT_STATUS_IS_OK(result))) {
-                
-               /* Return name */
-                
-               if ((names != NULL) && (name != NULL))
-                       fstrcpy(name, names[0]);
-                
-               /* Return name type */
-
-               if ((type != NULL) && (types != NULL))
-                       *type = types[0];
-
-               store_sid_by_name_in_cache(names[0], sid, types[0]);
-               store_name_by_sid_in_cache(sid, names[0], types[0]);
+               fstrcpy(dom_name, domain->name);
+               fstrcpy(name, names);
        } else {
-               /* OK, so we tried to look up a name in this sid, and
-                * didn't find it.  Therefore add a negative cache
-                * entry.  */
-               store_name_by_sid_in_cache(sid, "", SID_NAME_USE_NONE);
                *type = SID_NAME_UNKNOWN;
                fstrcpy(name, name_deadbeef);
        }
-
         
- done:
        talloc_destroy(mem_ctx);
 
        return rv;
 }
 
-/* Lookup user information from a rid */
-
-BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain, 
-                              TALLOC_CTX *mem_ctx, uint32 user_rid, 
-                              SAM_USERINFO_CTR **user_info)
-{
-       CLI_POLICY_HND *hnd;
-       uint16 info_level = 0x15;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-       POLICY_HND dom_pol, user_pol;
-       BOOL got_dom_pol = False, got_user_pol = False;
-
-       /* Get sam handle */
 
-       if (!(hnd = cm_get_sam_handle(domain->name)))
-               goto done;
-
-       /* Get domain handle */
-
-       result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                       des_access, &domain->sid, &dom_pol);
-
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       got_dom_pol = True;
-
-       /* Get user handle */
-
-       result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
-                                       des_access, user_rid, &user_pol);
-
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
+/* Free state information held for {set,get,end}{pw,gr}ent() functions */
 
-       /* Get user info */
+void free_getent_state(struct getent_state *state)
+{
+       struct getent_state *temp;
 
-       result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, 
-                                       info_level, user_info);
+       /* Iterate over state list */
 
-       cli_samr_close(hnd->cli, mem_ctx, &user_pol);
+       temp = state;
 
- done:
-       /* Clean up policy handles */
+       while(temp != NULL) {
+               struct getent_state *next;
 
-       if (got_user_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &user_pol);
+               /* Free sam entries then list entry */
 
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+               SAFE_FREE(state->sam_entries);
+               DLIST_REMOVE(state, state);
+               next = temp->next;
 
-       return NT_STATUS_IS_OK(result);
-}                                   
+               SAFE_FREE(temp);
+               temp = next;
+       }
+}
 
-/* Lookup groups a user is a member of.  I wish Unix had a call like this! */
+/* Parse winbindd related parameters */
 
-BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain,
-                                TALLOC_CTX *mem_ctx,
-                               uint32 user_rid, uint32 *num_groups,
-                               DOM_GID **user_groups)
+BOOL winbindd_param_init(void)
 {
-       CLI_POLICY_HND *hnd;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       POLICY_HND dom_pol, user_pol;
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-       BOOL got_dom_pol = False, got_user_pol = False;
+       /* Parse winbind uid and winbind_gid parameters */
 
-       /* Get sam handle */
-
-       if (!(hnd = cm_get_sam_handle(domain->name)))
-               goto done;
-
-       /* Get domain handle */
+       if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
+               DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
+               DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
+               return False;
+       }
+       
+       if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
+               DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
+               DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
+               return False;
+       }
+       
+       return True;
+}
 
-       result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                       des_access, &domain->sid, &dom_pol);
+/* Check if a domain is present in a comma-separated list of domains */
 
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
+BOOL check_domain_env(char *domain_env, char *domain)
+{
+       fstring name;
+       const char *tmp = domain_env;
 
-       got_dom_pol = True;
+       while(next_token(&tmp, name, ",", sizeof(fstring))) {
+               if (strequal(name, domain))
+                       return True;
+       }
 
-       /* Get user handle */
+       return False;
+}
 
-       result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
-                                       des_access, user_rid, &user_pol);
+/* Parse a string of the form DOMAIN/user into a domain and a user */
 
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
+BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
+{
+       char *p = strchr(domuser,*lp_winbind_separator());
 
-       got_user_pol = True;
+       if (!(p || lp_winbind_use_default_domain()))
+               return False;
+       
+       if(!p && lp_winbind_use_default_domain()) {
+               fstrcpy(user, domuser);
+               fstrcpy(domain, lp_workgroup());
+       } else {
+               fstrcpy(user, p+1);
+               fstrcpy(domain, domuser);
+               domain[PTR_DIFF(p, domuser)] = 0;
+       }
+       strupper(domain);
+       return True;
+}
 
-       /* Query user rids */
+/*
+    Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
+    'winbind separator' options.
+    This means:
+       - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
+       lp_workgroup
+        
+*/
+void fill_domain_username(fstring name, const char *domain, const char *user)
+{
+       if(lp_winbind_use_default_domain() &&
+           !strcmp(lp_workgroup(), domain)) {
+               strlcpy(name, user, sizeof(fstring));
+       } else {
+               slprintf(name, sizeof(fstring) - 1, "%s%s%s",
+                        domain, lp_winbind_separator(),
+                        user);
+       }
+}
 
-       result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, 
-                                       num_groups, user_groups);
+/*
+ * Winbindd socket accessor functions
+ */
 
- done:
+char *get_winbind_priv_pipe_dir(void) 
+{
+       return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
+}
 
-       /* Clean up policy handles */
+/* Open the winbindd socket */
 
-       if (got_user_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &user_pol);
+static int _winbindd_socket = -1;
+static int _winbindd_priv_socket = -1;
 
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+int open_winbindd_socket(void)
+{
+       if (_winbindd_socket == -1) {
+               _winbindd_socket = create_pipe_sock(
+                       WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
+               DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
+                          _winbindd_socket));
+       }
 
-       return NT_STATUS_IS_OK(result);
+       return _winbindd_socket;
 }
 
-/* Lookup group membership given a rid.   */
-
-BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
-                              TALLOC_CTX *mem_ctx,
-                              uint32 group_rid, uint32 *num_names, 
-                              uint32 **rid_mem, char ***names, 
-                              uint32 **name_types)
+int open_winbindd_priv_socket(void)
 {
-        CLI_POLICY_HND *hnd;
-        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-        uint32 i, total_names = 0;
-        POLICY_HND dom_pol, group_pol;
-        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-        BOOL got_dom_pol = False, got_group_pol = False;
-
-        /* Get sam handle */
+       if (_winbindd_priv_socket == -1) {
+               _winbindd_priv_socket = create_pipe_sock(
+                       get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
+               DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
+                          _winbindd_priv_socket));
+       }
 
-        if (!(hnd = cm_get_sam_handle(domain->name)))
-                goto done;
+       return _winbindd_priv_socket;
+}
 
-        /* Get domain handle */
+/* Close the winbindd socket */
 
-        result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                      des_access, &domain->sid, &dom_pol);
+void close_winbindd_socket(void)
+{
+       if (_winbindd_socket != -1) {
+               DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
+                          _winbindd_socket));
+               close(_winbindd_socket);
+               _winbindd_socket = -1;
+       }
+       if (_winbindd_priv_socket != -1) {
+               DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
+                          _winbindd_priv_socket));
+               close(_winbindd_priv_socket);
+               _winbindd_priv_socket = -1;
+       }
+}
 
-        if (!NT_STATUS_IS_OK(result))
-                goto done;
+/*
+ * Client list accessor functions
+ */
 
-        got_dom_pol = True;
+static struct winbindd_cli_state *_client_list;
+static int _num_clients;
 
-        /* Get group handle */
+/* Return list of all connected clients */
 
-        result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
-                                     des_access, group_rid, &group_pol);
+struct winbindd_cli_state *winbindd_client_list(void)
+{
+       return _client_list;
+}
 
-        if (!NT_STATUS_IS_OK(result))
-                goto done;
+/* Add a connection to the list */
 
-        got_group_pol = True;
+void winbindd_add_client(struct winbindd_cli_state *cli)
+{
+       DLIST_ADD(_client_list, cli);
+       _num_clients++;
+}
 
-        /* Step #1: Get a list of user rids that are the members of the
-           group. */
+/* Remove a client from the list */
 
-        result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
-                                         &group_pol, num_names, rid_mem,
-                                         name_types);
+void winbindd_remove_client(struct winbindd_cli_state *cli)
+{
+       DLIST_REMOVE(_client_list, cli);
+       _num_clients--;
+}
 
-        if (!NT_STATUS_IS_OK(result))
-                goto done;
+/* Close all open clients */
 
-        /* Step #2: Convert list of rids into list of usernames.  Do this
-           in bunches of ~1000 to avoid crashing NT4.  It looks like there
-           is a buffer overflow or something like that lurking around
-           somewhere. */
+void winbindd_kill_all_clients(void)
+{
+       struct winbindd_cli_state *cl = winbindd_client_list();
 
-#define MAX_LOOKUP_RIDS 900
+       DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
 
-        *names = talloc(mem_ctx, *num_names * sizeof(char *));
-        *name_types = talloc(mem_ctx, *num_names * sizeof(uint32));
+       while (cl) {
+               struct winbindd_cli_state *next;
+               
+               next = cl->next;
+               winbindd_remove_client(cl);
+               cl = next;
+       }
+}
 
-        for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
-                int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
-                uint32 tmp_num_names = 0;
-                char **tmp_names = NULL;
-                uint32 *tmp_types = NULL;
+/* Return number of open clients */
 
-                /* Lookup a chunk of rids */
+int winbindd_num_clients(void)
+{
+       return _num_clients;
+}
 
-                result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
-                                              &dom_pol, 1000, /* flags */
-                                              num_lookup_rids,
-                                              &(*rid_mem)[i],
-                                              &tmp_num_names,
-                                              &tmp_names, &tmp_types);
+/* Help with RID -> SID conversion */
 
-                if (!NT_STATUS_IS_OK(result))
-                        goto done;
+DOM_SID *rid_to_talloced_sid(struct winbindd_domain *domain,
+                                   TALLOC_CTX *mem_ctx,
+                                   uint32 rid) 
+{
+       DOM_SID *sid;
+       sid = talloc(mem_ctx, sizeof(*sid));
+       if (!sid) {
+               smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n");
+       }
+       sid_copy(sid, &domain->sid);
+       sid_append_rid(sid, rid);
+       return sid;
+}
+       
+/*****************************************************************************
+ For idmap conversion: convert one record to new format
+ Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
+ instead of the SID.
+*****************************************************************************/
+static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+       struct winbindd_domain *domain;
+       char *p;
+       DOM_SID sid;
+       uint32 rid;
+       fstring keystr;
+       fstring dom_name;
+       TDB_DATA key2;
+       BOOL *failed = (BOOL *)state;
+
+       DEBUG(10,("Converting %s\n", key.dptr));
+
+       p = strchr(key.dptr, '/');
+       if (!p)
+               return 0;
+
+       *p = 0;
+       fstrcpy(dom_name, key.dptr);
+       *p++ = '/';
+
+       domain = find_domain_from_name(dom_name);
+       if (domain == NULL) {
+               /* We must delete the old record. */
+               DEBUG(0,("Unable to find domain %s\n", dom_name ));
+               DEBUG(0,("deleting record %s\n", key.dptr ));
+
+               if (tdb_delete(tdb, key) != 0) {
+                       DEBUG(0, ("Unable to delete record %s\n", key.dptr));
+                       *failed = True;
+                       return -1;
+               }
 
-                /* Copy result into array.  The talloc system will take
-                   care of freeing the temporary arrays later on. */
+               return 0;
+       }
 
-                memcpy(&(*names)[i], tmp_names, sizeof(char *) * 
-                       tmp_num_names);
+       rid = atoi(p);
 
-                memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
-                       tmp_num_names);
+       sid_copy(&sid, &domain->sid);
+       sid_append_rid(&sid, rid);
 
-                total_names += tmp_num_names;
-        }
+       sid_to_string(keystr, &sid);
+       key2.dptr = keystr;
+       key2.dsize = strlen(keystr) + 1;
 
-        *num_names = total_names;
+       if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
+               DEBUG(0,("Unable to add record %s\n", key2.dptr ));
+               *failed = True;
+               return -1;
+       }
 
- done:
-        if (got_group_pol)
-                cli_samr_close(hnd->cli, mem_ctx, &group_pol);
+       if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
+               DEBUG(0,("Unable to update record %s\n", data.dptr ));
+               *failed = True;
+               return -1;
+       }
 
-        if (got_dom_pol)
-                cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+       if (tdb_delete(tdb, key) != 0) {
+               DEBUG(0,("Unable to delete record %s\n", key.dptr ));
+               *failed = True;
+               return -1;
+       }
 
-        return NT_STATUS_IS_OK(result);
+       return 0;
 }
 
-/* Free state information held for {set,get,end}{pw,gr}ent() functions */
+/* These definitions are from sam/idmap_tdb.c. Replicated here just
+   out of laziness.... :-( */
 
-void free_getent_state(struct getent_state *state)
-{
-       struct getent_state *temp;
-
-       /* Iterate over state list */
+/* High water mark keys */
+#define HWM_GROUP  "GROUP HWM"
+#define HWM_USER   "USER HWM"
 
-       temp = state;
+/* idmap version determines auto-conversion */
+#define IDMAP_VERSION 2
 
-       while(temp != NULL) {
-               struct getent_state *next;
-
-               /* Free sam entries then list entry */
-
-               SAFE_FREE(state->sam_entries);
-               DLIST_REMOVE(state, state);
-               next = temp->next;
-
-               SAFE_FREE(temp);
-               temp = next;
-       }
-}
 
-/* Initialise trusted domain info */
+/*****************************************************************************
+ Convert the idmap database from an older version.
+*****************************************************************************/
 
-BOOL winbindd_param_init(void)
+static BOOL idmap_convert(const char *idmap_name)
 {
-    /* Parse winbind uid and winbind_gid parameters */
-
-    if (!lp_winbind_uid(&server_state.uid_low, &server_state.uid_high)) {
-            DEBUG(0, ("winbind uid range missing or invalid\n"));
-            return False;
-    }
-
-    if (!lp_winbind_gid(&server_state.gid_low, &server_state.gid_high)) {
-            DEBUG(0, ("winbind gid range missing or invalid\n"));
-            return False;
-    }
-    
-    return True;
-}
+       int32 vers;
+       BOOL bigendianheader;
+       BOOL failed = False;
+       TDB_CONTEXT *idmap_tdb;
+
+       if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
+                                       TDB_DEFAULT, O_RDWR,
+                                       0600))) {
+               DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
+               return False;
+       }
 
-/* Query display info for a domain.  This returns enough information plus a
-   bit extra to give an overview of domain users for the User Manager
-   application. */
+       bigendianheader = (idmap_tdb->flags & TDB_BIGENDIAN) ? True : False;
 
-NTSTATUS winbindd_query_dispinfo(struct winbindd_domain *domain,
-                                 TALLOC_CTX *mem_ctx,
-                                uint32 *start_ndx, uint32 *num_entries, 
-                                WINBIND_DISPINFO **info)
-{
-       CLI_POLICY_HND *hnd;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       POLICY_HND dom_pol;
-       BOOL got_dom_pol = False;
-       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-       SAM_DISPINFO_CTR ctr;
-       SAM_DISPINFO_1 info1;
-       int i;
+       vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
 
-       /* Get sam handle */
+       if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
+               /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
+               /*
+                * high and low records were created on a
+                * big endian machine and will need byte-reversing.
+                */
 
-       if (!(hnd = cm_get_sam_handle(domain->name)))
-               goto done;
+               int32 wm;
 
-       /* Get domain handle */
+               wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
 
-       result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
-                                       des_access, &domain->sid, &dom_pol);
+               if (wm != -1) {
+                       wm = IREV(wm);
+               }  else {
+                       wm = server_state.uid_low;
+               }
 
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
+               if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
+                       DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
+                       tdb_close(idmap_tdb);
+                       return False;
+               }
 
-       got_dom_pol = True;
+               wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
+               if (wm != -1) {
+                       wm = IREV(wm);
+               } else {
+                       wm = server_state.gid_low;
+               }
 
-       ctr.sam.info1 = &info1;
+               if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
+                       DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
+                       tdb_close(idmap_tdb);
+                       return False;
+               }
+       }
 
-       /* Query display info level 1 */
-       result = cli_samr_query_dispinfo(hnd->cli, mem_ctx,
-                                       &dom_pol, start_ndx, 1,
-                                       num_entries, 0xffff, &ctr);
+       /* the old format stored as DOMAIN/rid - now we store the SID direct */
+       tdb_traverse(idmap_tdb, convert_fn, &failed);
 
-       /* now map the result into the WINBIND_DISPINFO structure */
-       (*info) = (WINBIND_DISPINFO *)talloc(mem_ctx, (*num_entries)*sizeof(WINBIND_DISPINFO));
-       if (!(*info)) {
-               return NT_STATUS_NO_MEMORY;
+       if (failed) {
+               DEBUG(0, ("Problem during conversion\n"));
+               tdb_close(idmap_tdb);
+               return False;
        }
 
-       for (i=0;i<*num_entries;i++) {
-               (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[i].uni_acct_name);
-               (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[i].uni_full_name);
-               (*info)[i].user_rid = info1.sam[i].rid_user;
-               /* For the moment we set the primary group for every user to be the
-                  Domain Users group.  There are serious problems with determining
-                  the actual primary group for large domains.  This should really
-                  be made into a 'winbind force group' smb.conf parameter or
-                  something like that. */ 
-               (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
+       if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
+               DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
+               tdb_close(idmap_tdb);
+               return False;
        }
 
- done:
-
-       if (got_dom_pol)
-               cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
-
-       return result;
+       tdb_close(idmap_tdb);
+       return True;
 }
 
-/* Check if a domain is present in a comma-separated list of domains */
+/*****************************************************************************
+ Convert the idmap database from an older version if necessary
+*****************************************************************************/
 
-BOOL check_domain_env(char *domain_env, char *domain)
+BOOL winbindd_upgrade_idmap(void)
 {
-       fstring name;
-       char *tmp = domain_env;
+       pstring idmap_name;
+       pstring backup_name;
+       SMB_STRUCT_STAT stbuf;
+       TDB_CONTEXT *idmap_tdb;
 
-       while(next_token(&tmp, name, ",", sizeof(fstring))) {
-               if (strequal(name, domain))
-                       return True;
-       }
+       pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
 
-       return False;
-}
+       if (!file_exist(idmap_name, &stbuf)) {
+               /* nothing to convert return */
+               return True;
+       }
 
-/* Parse a string of the form DOMAIN/user into a domain and a user */
+       if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
+                                       TDB_DEFAULT, O_RDWR,
+                                       0600))) {
+               DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
+               return False;
+       }
 
-void parse_domain_user(char *domuser, fstring domain, fstring user)
-{
-       char *p;
-       char *sep = lp_winbind_separator();
+       if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
+               /* nothing to convert return */
+               tdb_close(idmap_tdb);
+               return True;
+       }
 
-       if (!sep) 
-               sep = "\\";
+       /* backup_tdb expects the tdb not to be open */
+       tdb_close(idmap_tdb);
 
-       p = strchr(domuser,*sep);
+       DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
 
-       if (!p) 
-               p = strchr(domuser,'\\');
+       pstrcpy(backup_name, idmap_name);
+       pstrcat(backup_name, ".bak");
 
-       if (!p) {
-               fstrcpy(domain,"");
-               fstrcpy(user, domuser);
-               return;
+       if (backup_tdb(idmap_name, backup_name) != 0) {
+               DEBUG(0, ("Could not backup idmap database\n"));
+               return False;
        }
-       
-       fstrcpy(user, p+1);
-       fstrcpy(domain, domuser);
-       domain[PTR_DIFF(p, domuser)] = 0;
-       strupper(domain);
+
+       return idmap_convert(idmap_name);
 }