s3-passdb: cleanup some callers of pdb_get_trusteddom_pw().
[ira/wip.git] / source3 / winbindd / winbindd_ads.c
index ae8ad9dd1a868edf2ebc7e62886d0a92597ff42c..b2716716656ecd760c544d13b859a18290b408b3 100644 (file)
@@ -6,17 +6,17 @@
    Copyright (C) Andrew Tridgell 2001
    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
    Copyright (C) Gerald (Jerry) Carter 2004
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@@ -84,10 +84,8 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
        SAFE_FREE(ads->auth.realm);
 
        if ( IS_DC ) {
-               DOM_SID sid;
-               time_t last_set_time;
 
-               if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, &sid, &last_set_time ) ) {
+               if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) {
                        ads_destroy( &ads );
                        return NULL;
                }
@@ -153,7 +151,7 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
 static NTSTATUS query_user_list(struct winbindd_domain *domain,
                               TALLOC_CTX *mem_ctx,
                               uint32 *num_entries, 
-                              WINBIND_USERINFO **info)
+                              struct wbint_userinfo **info)
 {
        ADS_STRUCT *ads = NULL;
        const char *attrs[] = { "*", NULL };
@@ -174,7 +172,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
        }
 
        ads = ads_cached_connection(domain);
-       
+
        if (!ads) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                goto done;
@@ -192,7 +190,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                goto done;
        }
 
-       (*info) = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, count);
+       (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count);
        if (!*info) {
                status = NT_STATUS_NO_MEMORY;
                goto done;
@@ -201,16 +199,17 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
        i = 0;
 
        for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
-               char *name, *gecos = NULL;
-               char *homedir = NULL;
-               char *shell = NULL;
+               const char *name;
+               const char *gecos = NULL;
+               const char *homedir = NULL;
+               const char *shell = NULL;
                uint32 group;
                uint32 atype;
                DOM_SID user_sid;
                gid_t primary_gid = (gid_t)-1;
 
                if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
-                   ads_atype_map(atype) != SID_NAME_USER) {
+                   ds_atype_map(atype) != SID_NAME_USER) {
                        DEBUG(1,("Not a user account? atype=0x%x\n", atype));
                        continue;
                }
@@ -226,7 +225,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                if (gecos == NULL) {
                        gecos = ads_pull_string(ads, mem_ctx, msg, "name");
                }
-       
+
                if (!ads_pull_sid(ads, msg, "objectSid",
                                  &(*info)[i].user_sid)) {
                        DEBUG(1,("No sid for %s !?\n", name));
@@ -343,7 +342,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
        }
 
        i = 0;
-       
+
        for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
                char *name, *gecos;
                DOM_SID sid;
@@ -393,14 +392,55 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
         * using LDAP.
         *
         * if we ever need to enumerate domain local groups separately, 
-        * then this the optimization in enum_dom_groups() will need 
+        * then this optimization in enum_dom_groups() will need
         * to be split out
         */
        *num_entries = 0;
-       
+
        return NT_STATUS_OK;
 }
 
+/* convert a single name to a sid in a domain - use rpc methods */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+                           TALLOC_CTX *mem_ctx,
+                           const char *domain_name,
+                           const char *name,
+                           uint32_t flags,
+                           DOM_SID *sid,
+                           enum lsa_SidType *type)
+{
+       return reconnect_methods.name_to_sid(domain, mem_ctx,
+                                            domain_name, name, flags,
+                                            sid, type);
+}
+
+/* convert a domain SID to a user or group name - use rpc methods */
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+                           TALLOC_CTX *mem_ctx,
+                           const DOM_SID *sid,
+                           char **domain_name,
+                           char **name,
+                           enum lsa_SidType *type)
+{
+       return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
+                                            domain_name, name, type);
+}
+
+/* convert a list of rids to names - use rpc methods */
+static NTSTATUS rids_to_names(struct winbindd_domain *domain,
+                             TALLOC_CTX *mem_ctx,
+                             const DOM_SID *sid,
+                             uint32 *rids,
+                             size_t num_rids,
+                             char **domain_name,
+                             char ***names,
+                             enum lsa_SidType **types)
+{
+       return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
+                                              rids, num_rids,
+                                              domain_name, names, types);
+}
+
 /* If you are looking for "dn_lookup": Yes, it used to be here!
  * It has gone now since it was a major speed bottleneck in
  * lookup_groupmem (its only use). It has been replaced by
@@ -410,7 +450,7 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
 static NTSTATUS query_user(struct winbindd_domain *domain, 
                           TALLOC_CTX *mem_ctx, 
                           const DOM_SID *sid, 
-                          WINBIND_USERINFO *info)
+                          struct wbint_userinfo *info)
 {
        ADS_STRUCT *ads = NULL;
        const char *attrs[] = { "*", NULL };
@@ -422,6 +462,7 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        uint32 group_rid;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        struct netr_SamInfo3 *user = NULL;
+       gid_t gid;
 
        DEBUG(3,("ads: query_user\n"));
 
@@ -430,25 +471,25 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        info->primary_gid = (gid_t)-1;
 
        /* try netsamlogon cache first */
-                       
+
        if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) 
        {
-                               
                DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
                         sid_string_dbg(sid)));
 
                sid_compose(&info->user_sid, &domain->sid, user->base.rid);
                sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
-                               
+
                info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
                info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
-               
+
                nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
                              &info->homedir, &info->shell, &info->full_name, 
-                             &info->primary_gid );     
+                             &gid );
+               info->primary_gid = gid;
 
                TALLOC_FREE(user);
-                               
+
                return NT_STATUS_OK;
        }
 
@@ -470,7 +511,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
 
                nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
                              &info->homedir, &info->shell, &info->full_name, 
-                             &info->primary_gid );
+                             &gid);
+               info->primary_gid = gid;
 
                status = NT_STATUS_OK;
                goto done;
@@ -483,11 +525,14 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
                goto done;
        }
 
-       sidstr = sid_binstring(sid);
-       asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
+       sidstr = sid_binstring(talloc_tos(), sid);
+       if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
        rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
        free(ldap_exp);
-       free(sidstr);
+       TALLOC_FREE(sidstr);
        if (!ADS_ERR_OK(rc) || !msg) {
                DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
                         sid_string_dbg(sid), ads_errstr(rc)));
@@ -505,7 +550,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
 
        nss_get_info_cached( domain, sid, mem_ctx, ads, msg, 
                      &info->homedir, &info->shell, &info->full_name, 
-                     &info->primary_gid );     
+                     &gid);
+       info->primary_gid = gid;
 
        if (info->full_name == NULL) {
                info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
@@ -564,7 +610,7 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
                goto done;
        }
 
-       if (!(escaped_dn = escape_ldap_string_alloc(user_dn))) {
+       if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
                status = NT_STATUS_NO_MEMORY;
                goto done;
        }
@@ -576,22 +622,22 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
                GROUP_TYPE_SECURITY_ENABLED);
        if (!ldap_exp) {
                DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
-               SAFE_FREE(escaped_dn);
+               TALLOC_FREE(escaped_dn);
                status = NT_STATUS_NO_MEMORY;
                goto done;
        }
 
-       SAFE_FREE(escaped_dn);
+       TALLOC_FREE(escaped_dn);
 
        rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
-       
+
        if (!ADS_ERR_OK(rc) || !res) {
                DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
                return ads_ntstatus(rc);
        }
-       
+
        count = ads_count_replies(ads, res);
-       
+
        *user_sids = NULL;
        num_groups = 0;
 
@@ -606,12 +652,12 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
                for (msg = ads_first_entry(ads, res); msg;
                     msg = ads_next_entry(ads, msg)) {
                        DOM_SID group_sid;
-               
+
                        if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
                                DEBUG(1,("No sid for this group ?!?\n"));
                                continue;
                        }
-       
+
                        /* ignore Builtin groups from ADS - Guenther */
                        if (sid_check_is_in_builtin(&group_sid)) {
                                continue;
@@ -641,9 +687,10 @@ done:
    tokenGroups are not available. */
 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
                                           TALLOC_CTX *mem_ctx,
-                                          const char *user_dn, 
+                                          const char *user_dn,
                                           DOM_SID *primary_group,
-                                          size_t *p_num_groups, DOM_SID **user_sids)
+                                          size_t *p_num_groups,
+                                          DOM_SID **user_sids)
 {
        ADS_STATUS rc;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -652,15 +699,15 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
        size_t num_groups = 0;
        DOM_SID *group_sids = NULL;
        int i;
-       char **strings;
-       size_t num_strings = 0;
+       char **strings = NULL;
+       size_t num_strings = 0, num_sids = 0;
 
 
        DEBUG(3,("ads: lookup_usergroups_memberof\n"));
 
        if ( !winbindd_can_contact_domain( domain ) ) {
-               DEBUG(10,("lookup_usergroups_memberof: No incoming trust for domain %s\n",
-                         domain->name));               
+               DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
+                         "domain %s\n", domain->name));
                return NT_STATUS_OK;
        }
 
@@ -668,19 +715,19 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
 
        if (!ads) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
-               goto done;
+               return NT_STATUS_UNSUCCESSFUL;
        }
 
-       rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs, 
-                                                ADS_EXTENDED_DN_HEX_STRING, 
+       rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
+                                                ADS_EXTENDED_DN_HEX_STRING,
                                                 &strings, &num_strings);
 
        if (!ADS_ERR_OK(rc)) {
-               DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n", 
-                       user_dn, ads_errstr(rc)));
+               DEBUG(1,("lookup_usergroups_memberof ads_search "
+                       "member=%s: %s\n", user_dn, ads_errstr(rc)));
                return ads_ntstatus(rc);
        }
-       
+
        *user_sids = NULL;
        num_groups = 0;
 
@@ -693,21 +740,26 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
 
        group_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_strings + 1);
        if (!group_sids) {
-               TALLOC_FREE(strings);
                status = NT_STATUS_NO_MEMORY;
                goto done;
        }
 
        for (i=0; i<num_strings; i++) {
-
-               if (!ads_get_sid_from_extended_dn(mem_ctx, strings[i], 
-                                                 ADS_EXTENDED_DN_HEX_STRING, 
-                                                 &(group_sids)[i])) {
-                       TALLOC_FREE(group_sids);
-                       TALLOC_FREE(strings);
-                       status = NT_STATUS_NO_MEMORY;
-                       goto done;
+               rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
+                                                 ADS_EXTENDED_DN_HEX_STRING,
+                                                 &(group_sids)[i]);
+               if (!ADS_ERR_OK(rc)) {
+                       /* ignore members without SIDs */
+                       if (NT_STATUS_EQUAL(ads_ntstatus(rc),
+                           NT_STATUS_NOT_FOUND)) {
+                               continue;
+                       }
+                       else {
+                               status = ads_ntstatus(rc);
+                               goto done;
+                       }
                }
+               num_sids++;
        }
 
        if (i == 0) {
@@ -716,7 +768,7 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
                goto done;
        }
 
-       for (i=0; i<num_strings; i++) {
+       for (i=0; i<num_sids; i++) {
 
                /* ignore Builtin groups from ADS - Guenther */
                if (sid_check_is_in_builtin(&group_sids[i])) {
@@ -728,14 +780,17 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
                if (!NT_STATUS_IS_OK(status)) {
                        goto done;
                }
-       
+
        }
 
        *p_num_groups = num_groups;
        status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
 
-       DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn));
+       DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
+               user_dn));
+
 done:
+       TALLOC_FREE(strings);
        TALLOC_FREE(group_sids);
 
        return status;
@@ -780,7 +835,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        }
 
        ads = ads_cached_connection(domain);
-       
+
        if (!ads) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                status = NT_STATUS_SERVER_DISABLED;
@@ -795,7 +850,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                          "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
                goto done;
        }
-       
+
        count = ads_count_replies(ads, msg);
        if (count != 1) {
                status = NT_STATUS_UNSUCCESSFUL;
@@ -812,7 +867,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                goto done;
        }
 
-       user_dn = ads_get_dn(ads, msg);
+       user_dn = ads_get_dn(ads, mem_ctx, msg);
        if (user_dn == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto done;
@@ -838,7 +893,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        if (count == 0) {
 
                /* no tokenGroups */
-               
+
                /* lookup what groups this user is a member of by DN search on
                 * "memberOf" */
 
@@ -868,7 +923,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
-       
+
        for (i=0;i<count;i++) {
 
                /* ignore Builtin groups from ADS - Guenther */
@@ -889,18 +944,32 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
                 sid_string_dbg(sid)));
 done:
-       ads_memfree(ads, user_dn);
+       TALLOC_FREE(user_dn);
        ads_msgfree(ads, msg);
        return status;
 }
 
+/* Lookup aliases a user is member of - use rpc methods */
+static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
+                                  TALLOC_CTX *mem_ctx,
+                                  uint32 num_sids, const DOM_SID *sids,
+                                  uint32 *num_aliases, uint32 **alias_rids)
+{
+       return reconnect_methods.lookup_useraliases(domain, mem_ctx,
+                                                   num_sids, sids,
+                                                   num_aliases,
+                                                   alias_rids);
+}
+
 /*
   find the members of a group, given a group rid and domain
  */
 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
-                               const DOM_SID *group_sid, uint32 *num_names, 
-                               DOM_SID **sid_mem, char ***names, 
+                               const DOM_SID *group_sid,
+                               enum lsa_SidType type,
+                               uint32 *num_names,
+                               DOM_SID **sid_mem, char ***names,
                                uint32 **name_types)
 {
        ADS_STATUS rc;
@@ -912,8 +981,6 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        int i;
        size_t num_members = 0;
        ads_control args;
-        struct rpc_pipe_client *cli;
-        POLICY_HND lsa_policy;
        DOM_SID *sid_mem_nocache = NULL;
        char **names_nocache = NULL;
        enum lsa_SidType *name_types_nocache = NULL;
@@ -921,7 +988,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        uint32 num_nocache = 0;
        TALLOC_CTX *tmp_ctx = NULL;
 
-       DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name, 
+       DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
                  sid_string_dbg(group_sid)));
 
        *num_names = 0;
@@ -935,52 +1002,50 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 
        if ( !winbindd_can_contact_domain( domain ) ) {
                DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
-                         domain->name));               
+                         domain->name));
                return NT_STATUS_OK;
        }
 
        ads = ads_cached_connection(domain);
-       
+
        if (!ads) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                goto done;
        }
 
-       if ((sidbinstr = sid_binstring(group_sid)) == NULL) {
+       if ((sidbinstr = sid_binstring(talloc_tos(), group_sid)) == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto done;
        }
 
        /* search for all members of the group */
-       if (!(ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", 
-                                        sidbinstr))) 
-       {
-               SAFE_FREE(sidbinstr);
+       ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
+       TALLOC_FREE(sidbinstr);
+       if (ldap_exp == NULL) {
                DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
                status = NT_STATUS_NO_MEMORY;
                goto done;
        }
-       SAFE_FREE(sidbinstr);
 
        args.control = ADS_EXTENDED_DN_OID;
        args.val = ADS_EXTENDED_DN_HEX_STRING;
        args.critical = True;
 
-       rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path, 
+       rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
                               ldap_exp, &args, "member", &members, &num_members);
 
        if (!ADS_ERR_OK(rc)) {
                DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
                status = NT_STATUS_UNSUCCESSFUL;
                goto done;
-       } 
-       
+       }
+
        DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
-       
+
        /* Now that we have a list of sids, we need to get the
         * lists of names and name_types belonging to these sids.
-        * even though conceptually not quite clean,  we use the 
-        * RPC call lsa_lookup_sids for this since it can handle a 
+        * even though conceptually not quite clean,  we use the
+        * RPC call lsa_lookup_sids for this since it can handle a
         * list of sids. ldap calls can just resolve one sid at a time.
         *
         * At this stage, the sids are still hidden in the exetended dn
@@ -988,7 +1053,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
         * stated above: In extracting the sids from the member strings,
         * we try to resolve as many sids as possible from the
         * cache. Only the rest is passed to the lsa_lookup_sids call. */
-       
+
        if (num_members) {
                (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
                (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
@@ -1015,18 +1080,31 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                char *name, *domain_name;
                DOM_SID sid;
 
-               if (!ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val, &sid)) {
-                       status = NT_STATUS_INVALID_PARAMETER;
-                       goto done;
+               rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
+                   &sid);
+               if (!ADS_ERR_OK(rc)) {
+                       if (NT_STATUS_EQUAL(ads_ntstatus(rc),
+                           NT_STATUS_NOT_FOUND)) {
+                               /* Group members can be objects, like Exchange
+                                * Public Folders, that don't have a SID.  Skip
+                                * them. */
+                               continue;
+                       }
+                       else {
+                               status = ads_ntstatus(rc);
+                               goto done;
+                       }
                }
-               if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name, &name_type)) {
+               if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
+                   &name_type)) {
                        DEBUG(10,("ads: lookup_groupmem: got sid %s from "
                                  "cache\n", sid_string_dbg(&sid)));
                        sid_copy(&(*sid_mem)[*num_names], &sid);
-                       (*names)[*num_names] = talloc_asprintf(*names, "%s%c%s",
-                                                              domain_name,
-                                                              *lp_winbind_separator(),
-                                                              name );
+                       (*names)[*num_names] = fill_domain_username_talloc(
+                                                       *names,
+                                                       domain_name,
+                                                       name,
+                                                       true);
 
                        (*name_types)[*num_names] = name_type;
                        (*num_names)++;
@@ -1045,37 +1123,48 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        /* handle sids not resolved from cache by lsa_lookup_sids */
        if (num_nocache > 0) {
 
-               status = cm_connect_lsa(domain, tmp_ctx, &cli, &lsa_policy);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       goto done;
+               status = winbindd_lookup_sids(tmp_ctx,
+                                             domain,
+                                             num_nocache,
+                                             sid_mem_nocache,
+                                             &domains_nocache,
+                                             &names_nocache,
+                                             &name_types_nocache);
+
+               if (!(NT_STATUS_IS_OK(status) ||
+                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
+                     NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
+               {
+                       DEBUG(1, ("lsa_lookupsids call failed with %s "
+                                 "- retrying...\n", nt_errstr(status)));
+
+                       status = winbindd_lookup_sids(tmp_ctx,
+                                                     domain,
+                                                     num_nocache,
+                                                     sid_mem_nocache,
+                                                     &domains_nocache,
+                                                     &names_nocache,
+                                                     &name_types_nocache);
                }
 
-               status = rpccli_lsa_lookup_sids(cli, tmp_ctx, 
-                                               &lsa_policy,
-                                               num_nocache, 
-                                               sid_mem_nocache, 
-                                               &domains_nocache, 
-                                               &names_nocache, 
-                                               &name_types_nocache);
-
                if (NT_STATUS_IS_OK(status) ||
-                   NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) 
+                   NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
                {
-                       /* Copy the entries over from the "_nocache" arrays 
-                        * to the result arrays, skipping the gaps the 
+                       /* Copy the entries over from the "_nocache" arrays
+                        * to the result arrays, skipping the gaps the
                         * lookup_sids call left. */
                        for (i=0; i < num_nocache; i++) {
-                               if (((names_nocache)[i] != NULL) && 
-                                   ((name_types_nocache)[i] != SID_NAME_UNKNOWN)) 
+                               if (((names_nocache)[i] != NULL) &&
+                                   ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
                                {
                                        sid_copy(&(*sid_mem)[*num_names],
                                                 &sid_mem_nocache[i]);
-                                       (*names)[*num_names] = talloc_asprintf( *names, 
-                                                                               "%s%c%s",
-                                                                               domains_nocache[i],
-                                                                               *lp_winbind_separator(),
-                                                                               names_nocache[i] );
+                                       (*names)[*num_names] =
+                                               fill_domain_username_talloc(
+                                                       *names,
+                                                       domains_nocache[i],
+                                                       names_nocache[i],
+                                                       true);
                                        (*name_types)[*num_names] = name_types_nocache[i];
                                        (*num_names)++;
                                }
@@ -1125,16 +1214,16 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
        *seq = DOM_SEQUENCE_NONE;
 
        ads = ads_cached_connection(domain);
-       
+
        if (!ads) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                return NT_STATUS_UNSUCCESSFUL;
        }
 
        rc = ads_USN(ads, seq);
-       
+
        if (!ADS_ERR_OK(rc)) {
-       
+
                /* its a dead connection, destroy it */
 
                if (domain->private_data) {
@@ -1148,6 +1237,22 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
        return ads_ntstatus(rc);
 }
 
+/* find the lockout policy of a domain - use rpc methods */
+static NTSTATUS lockout_policy(struct winbindd_domain *domain,
+                              TALLOC_CTX *mem_ctx,
+                              struct samr_DomInfo12 *policy)
+{
+       return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
+}
+
+/* find the password policy of a domain - use rpc methods */
+static NTSTATUS password_policy(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct samr_DomInfo1 *policy)
+{
+       return reconnect_methods.password_policy(domain, mem_ctx, policy);
+}
+
 /* get a list of trusted domains */
 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
@@ -1163,7 +1268,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        struct rpc_pipe_client *cli;
        uint32                 fr_flags = (NETR_TRUST_FLAG_IN_FOREST | NETR_TRUST_FLAG_TREEROOT);
        int ret_count;
-       
+
        DEBUG(3,("ads: trusted_domains\n"));
 
        *num_domains = 0;
@@ -1195,7 +1300,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        }
 
        result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
-                                                     cli->cli->desthost,
+                                                     cli->desthost,
                                                      flags,
                                                      &trusts,
                                                      NULL);
@@ -1224,7 +1329,9 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                ret_count = 0;          
                for (i = 0; i < trusts.count; i++) {
                        struct winbindd_domain d;
-                       
+
+                       ZERO_STRUCT(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
@@ -1236,18 +1343,30 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                DEBUG(10,("trusted_domains: Skipping external trusted domain "
                                          "%s because it is outside of our primary domain\n",
                                          trusts.array[i].netbios_name));
-                               continue;                               
+                               continue;
                        }
-                       
+
+                       /* We must check that the SID of each trusted domain
+                        * was returned to work around a bug in Windows:
+                        * http://support.microsoft.com/kb/922832 */
+
                        (*names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].netbios_name);
                        (*alt_names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].dns_name);
-                       sid_copy(&(*dom_sids)[ret_count], trusts.array[i].sid);
+                       if (trusts.array[i].sid) {
+                               sid_copy(&(*dom_sids)[ret_count], trusts.array[i].sid);
+                       } else {
+                               sid_copy(&(*dom_sids)[ret_count], &global_sid_NULL);
+                       }
 
                        /* add to the trusted domain cache */
 
                        fstrcpy( d.name,  trusts.array[i].netbios_name);
                        fstrcpy( d.alt_name, trusts.array[i].dns_name);
-                       sid_copy( &d.sid, trusts.array[i].sid);
+                       if (trusts.array[i].sid) {
+                               sid_copy( &d.sid, trusts.array[i].sid);
+                       } else {
+                               sid_copy(&d.sid, &global_sid_NULL);
+                       }
 
                        if ( domain->primary ) {
                                DEBUG(10,("trusted_domains(ads):  Searching "
@@ -1310,7 +1429,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                        d.domain_trust_attribs = domain->domain_trust_attribs;
                                }
                                TALLOC_FREE(parent);
-                               
+
                                wcache_tdc_add_domain( &d );
                                ret_count++;
                        }
@@ -1328,16 +1447,16 @@ struct winbindd_methods ads_methods = {
        query_user_list,
        enum_dom_groups,
        enum_local_groups,
-       msrpc_name_to_sid,
-       msrpc_sid_to_name,
-       msrpc_rids_to_names,
+       name_to_sid,
+       sid_to_name,
+       rids_to_names,
        query_user,
        lookup_usergroups,
-       msrpc_lookup_useraliases,
+       lookup_useraliases,
        lookup_groupmem,
        sequence_number,
-       msrpc_lockout_policy,
-       msrpc_password_policy,
+       lockout_policy,
+       password_policy,
        trusted_domains,
 };