s3:winbindd: use winbindd_get_trust_credentials()/ads_connect_creds() in winbindd_ads.c
[metze/samba/wip.git] / source3 / winbindd / winbindd_ads.c
index fdb6806040eb9d952c02f59f9f7827386e46602b..7ade5718399dc41d61e8ef1c55a4b98b4bba2ad8 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "includes.h"
 #include "winbindd.h"
+#include "winbindd_ads.h"
+#include "libsmb/namequery.h"
 #include "rpc_client/rpc_client.h"
 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
 #include "../libds/common/flags.h"
@@ -32,6 +34,7 @@
 #include "../libds/common/flag_mapping.h"
 #include "libsmb/samlogon_cache.h"
 #include "passdb.h"
+#include "auth/credentials/credentials.h"
 
 #ifdef HAVE_ADS
 
@@ -41,8 +44,6 @@
 extern struct winbindd_methods reconnect_methods;
 extern struct winbindd_methods msrpc_methods;
 
-#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
-
 /**
  * Check if cached connection can be reused. If the connection cannot
  * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
@@ -56,7 +57,7 @@ static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
                time_t expire;
                time_t now = time(NULL);
 
-               expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
+               expire = nt_time_to_unix(ads->auth.expire_time);
 
                DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
                          "is now %d)\n", (uint32_t)expire - (uint32_t)now,
@@ -66,155 +67,159 @@ static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
                        return;
                } else {
                        /* we own this ADS_STRUCT so make sure it goes away */
-                       DEBUG(7,("Deleting expired krb5 credential cache\n"));
-                       ads->is_mine = True;
-                       ads_destroy( &ads );
-                       ads_kdestroy(WINBIND_CCACHE_NAME);
+                       DEBUG(7,("Deleting expired ads struct\n"));
+                       TALLOC_FREE(ads);
                        *adsp = NULL;
                }
        }
 }
 
+
+static NTSTATUS ads_cached_connection_reconnect_creds(struct ads_struct *ads,
+                                                     void *private_data,
+                                                     TALLOC_CTX *mem_ctx,
+                                                     struct cli_credentials **creds)
+{
+       struct winbindd_domain *target_domain = NULL;
+
+       if (ads->server.realm != NULL) {
+               target_domain = find_domain_from_name_noinit(ads->server.realm);
+       }
+       if (target_domain == NULL && ads->server.workgroup != NULL) {
+               target_domain = find_domain_from_name_noinit(ads->server.workgroup);
+       }
+
+       if (target_domain == NULL) {
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       return winbindd_get_trust_credentials(target_domain,
+                                             mem_ctx,
+                                             false, /* netlogon */
+                                             false, /* ipc_fallback */
+                                             creds);
+}
+
 /**
  * @brief Establish a connection to a DC
  *
  * @param[out]   adsp             ADS_STRUCT that will be created
- * @param[in]    target_realm     Realm of domain to connect to
- * @param[in]    target_dom_name  'workgroup' name of domain to connect to
+ * @param[in]    target_domain    target domain
  * @param[in]    ldap_server      DNS name of server to connect to
- * @param[in]    password         Our machine acount secret
+ * @param[in]    creds            credentials to use
  * @param[in]    auth_realm       Realm of local domain for creating krb token
- * @param[in]    renewable        Renewable ticket time
  *
  * @return ADS_STATUS
  */
-static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
-                                               const char *target_realm,
-                                               const char *target_dom_name,
+static ADS_STATUS ads_cached_connection_connect(struct winbindd_domain *target_domain,
                                                const char *ldap_server,
-                                               char *password,
-                                               char *auth_realm,
-                                               time_t renewable)
+                                               TALLOC_CTX *mem_ctx,
+                                               ADS_STRUCT **adsp)
 {
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char *target_realm = target_domain->alt_name;
+       const char *target_dom_name = target_domain->name;
+       struct cli_credentials *creds = NULL;
        ADS_STRUCT *ads;
        ADS_STATUS status;
+       NTSTATUS ntstatus;
        struct sockaddr_storage dc_ss;
        fstring dc_name;
 
-       if (auth_realm == NULL) {
-               return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
-       }
-
-       /* we don't want this to affect the users ccache */
-       setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
+       /* the machine acct password might have change - fetch it every time */
 
-       ads = ads_init(target_realm, target_dom_name, ldap_server);
+       ntstatus = winbindd_get_trust_credentials(target_domain,
+                                                 tmp_ctx,
+                                                 false, /* netlogon */
+                                                 false, /* ipc_fallback */
+                                                 &creds);
+       if (!NT_STATUS_IS_OK(ntstatus)) {
+               status = ADS_ERROR_NT(ntstatus);
+               goto out;
+       }
+
+       ads = ads_init(tmp_ctx,
+                      target_realm,
+                      target_dom_name,
+                      ldap_server,
+                      ADS_SASL_SEAL);
        if (!ads) {
                DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
-               return ADS_ERROR(LDAP_NO_MEMORY);
+               status = ADS_ERROR(LDAP_NO_MEMORY);
+               goto out;
        }
 
-       SAFE_FREE(ads->auth.password);
-       SAFE_FREE(ads->auth.realm);
-
-       ads->auth.renewable = renewable;
-       ads->auth.password = password;
-
-       ads->auth.realm = SMB_STRDUP(auth_realm);
-       if (!strupper_m(ads->auth.realm)) {
-               ads_destroy(&ads);
-               return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
-       }
+       ads_set_reconnect_fn(ads, ads_cached_connection_reconnect_creds, NULL);
 
        /* Setup the server affinity cache.  We don't reaally care
           about the name.  Just setup affinity and the KRB5_CONFIG
           file. */
        get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
 
-       status = ads_connect(ads);
+       status = ads_connect_creds(ads, creds);
        if (!ADS_ERR_OK(status)) {
                DEBUG(1,("ads_connect for domain %s failed: %s\n",
                         target_dom_name, ads_errstr(status)));
-               ads_destroy(&ads);
-               return status;
+               goto out;
        }
 
-       /* set the flag that says we don't own the memory even
-          though we do so that ads_destroy() won't destroy the
-          structure we pass back by reference */
-
-       ads->is_mine = False;
-
-       *adsp = ads;
-
+       *adsp = talloc_move(mem_ctx, &ads);
+out:
+       TALLOC_FREE(tmp_ctx);
        return status;
 }
 
-ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
+ADS_STATUS ads_idmap_cached_connection(const char *dom_name,
+                                      TALLOC_CTX *mem_ctx,
+                                      ADS_STRUCT **adsp)
 {
-       char *ldap_server, *realm, *password;
-       struct winbindd_domain *wb_dom;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       char *ldap_server = NULL;
+       struct winbindd_domain *wb_dom = NULL;
        ADS_STATUS status;
 
+       if (IS_AD_DC) {
+               /*
+                * Make sure we never try to use LDAP against
+                * a trusted domain as AD DC.
+                */
+               TALLOC_FREE(tmp_ctx);
+               return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
+       }
+
        ads_cached_connection_reuse(adsp);
        if (*adsp != NULL) {
+               TALLOC_FREE(tmp_ctx);
                return ADS_SUCCESS;
        }
 
        /*
         * At this point we only have the NetBIOS domain name.
-        * Check if we can get server nam and realm from SAF cache
+        * Check if we can get server name and realm from SAF cache
         * and the domain list.
         */
-       ldap_server = saf_fetch(talloc_tos(), dom_name);
-       DEBUG(10, ("ldap_server from saf cache: '%s'\n",
-                  ldap_server ? ldap_server : ""));
+       ldap_server = saf_fetch(tmp_ctx, dom_name);
+
+       DBG_DEBUG("ldap_server from saf cache: '%s'\n",
+                  ldap_server ? ldap_server : "");
 
        wb_dom = find_domain_from_name(dom_name);
        if (wb_dom == NULL) {
-               DEBUG(10, ("could not find domain '%s'\n", dom_name));
+               DBG_DEBUG("could not find domain '%s'\n", dom_name);
+               TALLOC_FREE(tmp_ctx);
                return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
        }
 
-       DEBUG(10, ("find_domain_from_name found realm '%s' for "
-                         " domain '%s'\n", wb_dom->alt_name, dom_name));
-
-       if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
-               TALLOC_FREE(ldap_server);
-               return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
-       }
-
-       if (IS_DC) {
-               SMB_ASSERT(wb_dom->alt_name != NULL);
-               realm = SMB_STRDUP(wb_dom->alt_name);
-       } else {
-               struct winbindd_domain *our_domain = wb_dom;
-
-               /* always give preference to the alt_name in our
-                  primary domain if possible */
-
-               if (!wb_dom->primary) {
-                       our_domain = find_our_domain();
-               }
-
-               if (our_domain->alt_name != NULL) {
-                       realm = SMB_STRDUP(our_domain->alt_name);
-               } else {
-                       realm = SMB_STRDUP(lp_realm());
-               }
-       }
+       DBG_DEBUG("find_domain_from_name found realm '%s' for "
+                 " domain '%s'\n", wb_dom->alt_name, dom_name);
 
        status = ads_cached_connection_connect(
-               adsp,                   /* Returns ads struct. */
-               wb_dom->alt_name,       /* realm to connect to. */
-               dom_name,               /* 'workgroup' name for ads_init */
+               wb_dom,
                ldap_server,            /* DNS name to connect to. */
-               password,               /* password for auth realm. */
-               realm,                  /* realm used for krb5 ticket. */
-               0);                     /* renewable ticket time. */
+               mem_ctx,                /* memory context for ads struct */
+               adsp);                  /* Returns ads struct. */
 
-       SAFE_FREE(realm);
-       TALLOC_FREE(ldap_server);
+       TALLOC_FREE(tmp_ctx);
 
        return status;
 }
@@ -223,95 +228,78 @@ ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
   return our ads connections structure for a domain. We keep the connection
   open to make things faster
 */
-static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
+static ADS_STATUS ads_cached_connection(struct winbindd_domain *domain,
+                                       ADS_STRUCT **adsp)
 {
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
        ADS_STATUS status;
-       char *password, *realm;
-
-       DEBUG(10,("ads_cached_connection\n"));
-       ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
-
-       if (domain->private_data) {
-               return (ADS_STRUCT *)domain->private_data;
-       }
-
-       /* the machine acct password might have change - fetch it every time */
-
-       if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
-               return NULL;
-       }
 
-       if ( IS_DC ) {
-               SMB_ASSERT(domain->alt_name != NULL);
-               realm = SMB_STRDUP(domain->alt_name);
+       if (IS_AD_DC) {
+               /*
+                * Make sure we never try to use LDAP against
+                * a trusted domain as AD DC.
+                */
+               TALLOC_FREE(tmp_ctx);
+               return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
        }
-       else {
-               struct winbindd_domain *our_domain = domain;
 
+       DBG_DEBUG("ads_cached_connection\n");
 
-               /* always give preference to the alt_name in our
-                  primary domain if possible */
-
-               if ( !domain->primary )
-                       our_domain = find_our_domain();
-
-               if (our_domain->alt_name != NULL) {
-                       realm = SMB_STRDUP( our_domain->alt_name );
-               }
-               else
-                       realm = SMB_STRDUP( lp_realm() );
+       ads_cached_connection_reuse(&domain->backend_data.ads_conn);
+       if (domain->backend_data.ads_conn != NULL) {
+               *adsp = domain->backend_data.ads_conn;
+               TALLOC_FREE(tmp_ctx);
+               return ADS_SUCCESS;
        }
 
        status = ads_cached_connection_connect(
-                                       (ADS_STRUCT **)&domain->private_data,
-                                       domain->alt_name,
-                                       domain->name, NULL,
-                                       password, realm,
-                                       WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
-       SAFE_FREE(realm);
-
+                                       domain,
+                                       NULL,
+                                       domain,
+                                       &domain->backend_data.ads_conn);
        if (!ADS_ERR_OK(status)) {
                /* if we get ECONNREFUSED then it might be a NT4
                    server, fall back to MSRPC */
                if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
                    status.err.rc == ECONNREFUSED) {
                        /* 'reconnect_methods' is the MS-RPC backend. */
-                       DEBUG(1,("Trying MSRPC methods\n"));
+                       DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
+                                  domain->name);
                        domain->backend = &reconnect_methods;
                }
-               return NULL;
+               TALLOC_FREE(tmp_ctx);
+               return status;
        }
 
-       return (ADS_STRUCT *)domain->private_data;
+       *adsp = domain->backend_data.ads_conn;
+       TALLOC_FREE(tmp_ctx);
+       return ADS_SUCCESS;
 }
 
 /* Query display info for a realm. This is the basic user list fn */
 static NTSTATUS query_user_list(struct winbindd_domain *domain,
                               TALLOC_CTX *mem_ctx,
-                              uint32_t *num_entries,
-                              struct wbint_userinfo **pinfo)
+                              uint32_t **prids)
 {
        ADS_STRUCT *ads = NULL;
-       const char *attrs[] = { "*", NULL };
-       int i, count;
+       const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
+       int count;
+       uint32_t *rids = NULL;
        ADS_STATUS rc;
        LDAPMessage *res = NULL;
        LDAPMessage *msg = NULL;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 
-       *num_entries = 0;
-
        DEBUG(3,("ads: query_user_list\n"));
 
        if ( !winbindd_can_contact_domain( domain ) ) {
                DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
-                         domain->name));               
+                         domain->name));
                return NT_STATUS_OK;
        }
 
-       ads = ads_cached_connection(domain);
-
-       if (!ads) {
+       rc = ads_cached_connection(domain, &ads);
+       if (!ADS_ERR_OK(rc)) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                goto done;
        }
@@ -332,8 +320,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                goto done;
        }
 
-       (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
-       if (!*pinfo) {
+       rids = talloc_zero_array(mem_ctx, uint32_t, count);
+       if (rids == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto done;
        }
@@ -341,8 +329,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
        count = 0;
 
        for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
-               struct wbint_userinfo *info = &((*pinfo)[count]);
-               uint32_t group;
+               struct dom_sid user_sid;
                uint32_t atype;
                bool ok;
 
@@ -356,61 +343,38 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                        continue;
                }
 
-               info->acct_name = ads_pull_username(ads, mem_ctx, msg);
-               info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
-               if (info->full_name == NULL) {
-                       info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
-               }
-               info->homedir = NULL;
-               info->shell = NULL;
-               info->primary_gid = (gid_t)-1;
-
-               if (!ads_pull_sid(ads, msg, "objectSid",
-                                 &info->user_sid)) {
-                       DEBUG(1, ("No sid for %s !?\n", info->acct_name));
+               if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
+                       char *dn = ads_get_dn(ads, talloc_tos(), msg);
+                       DBG_INFO("No sid for %s !?\n", dn);
+                       TALLOC_FREE(dn);
                        continue;
                }
 
-               if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
-                       DEBUG(1, ("No primary group for %s !?\n",
-                                 info->acct_name));
+               if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
+                       struct dom_sid_buf sidstr, domstr;
+                       DBG_WARNING("Got sid %s in domain %s\n",
+                                   dom_sid_str_buf(&user_sid, &sidstr),
+                                   dom_sid_str_buf(&domain->sid, &domstr));
                        continue;
                }
-               sid_compose(&info->group_sid, &domain->sid, group);
 
+               sid_split_rid(&user_sid, &rids[count]);
                count += 1;
        }
 
-       (*num_entries) = count;
-       ads_msgfree(ads, res);
-
-       for (i=0; i<count; i++) {
-               struct wbint_userinfo *info = &((*pinfo)[i]);
-               const char *gecos = NULL;
-               gid_t primary_gid = (gid_t)-1;
-
-               status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
-                                            &info->homedir, &info->shell,
-                                            &gecos, &primary_gid);
-               if (!NT_STATUS_IS_OK(status)) {
-                       /*
-                        * Deliberately ignore this error, there might be more
-                        * users to fill
-                        */
-                       continue;
-               }
-
-               if (gecos != NULL) {
-                       info->full_name = gecos;
-               }
-               info->primary_gid = primary_gid;
+       rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
+       if (prids != NULL) {
+               *prids = rids;
+       } else {
+               TALLOC_FREE(rids);
        }
 
        status = NT_STATUS_OK;
 
-       DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
+       DBG_NOTICE("ads query_user_list gave %d entries\n", count);
 
 done:
+       ads_msgfree(ads, res);
        return status;
 }
 
@@ -437,7 +401,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
 
        if ( !winbindd_can_contact_domain( domain ) ) {
                DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
-                         domain->name));               
+                         domain->name));
                return NT_STATUS_OK;
        }
 
@@ -452,7 +416,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
         * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
         * default value, it MUST be absent. In case of extensible matching the
         * "dnattr" boolean defaults to FALSE and so it must be only be present
-        * when set to TRUE. 
+        * when set to TRUE.
         *
         * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
         * filter using bitwise matching rule then the buggy AD fails to decode
@@ -463,9 +427,10 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
         *
         * Thanks to Ralf Haferkamp for input and testing - Guenther */
 
-       filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
-                                ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
-                                ADS_LDAP_MATCHING_RULE_BIT_AND, 
+       filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)"
+                                "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d)"
+                                "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))))",
+                                GROUP_TYPE_SECURITY_ENABLED,
                                 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
 
        if (filter == NULL) {
@@ -473,9 +438,8 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                goto done;
        }
 
-       ads = ads_cached_connection(domain);
-
-       if (!ads) {
+       rc = ads_cached_connection(domain, &ads);
+       if (!ADS_ERR_OK(rc)) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                goto done;
        }
@@ -509,8 +473,8 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                struct dom_sid sid;
                uint32_t rid;
 
-               name = ads_pull_username(ads, mem_ctx, msg);
-               gecos = ads_pull_string(ads, mem_ctx, msg, "name");
+               name = ads_pull_username(ads, (*info), msg);
+               gecos = ads_pull_string(ads, (*info), msg, "name");
                if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
                        DEBUG(1,("No sid for %s !?\n", name));
                        continue;
@@ -521,8 +485,8 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                        continue;
                }
 
-               fstrcpy((*info)[i].acct_name, name);
-               fstrcpy((*info)[i].acct_desc, gecos);
+               (*info)[i].acct_name = name;
+               (*info)[i].acct_desc = gecos;
                (*info)[i].rid = rid;
                i++;
        }
@@ -534,7 +498,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
        DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
 
 done:
-       if (res) 
+       if (res)
                ads_msgfree(ads, res);
 
        return status;
@@ -547,12 +511,12 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
                                struct wb_acct_info **info)
 {
        /*
-        * This is a stub function only as we returned the domain 
+        * This is a stub function only as we returned the domain
         * local groups in enum_dom_groups() if the domain->native field
         * was true.  This is a simple performance optimization when
         * using LDAP.
         *
-        * if we ever need to enumerate domain local groups separately, 
+        * if we ever need to enumerate domain local groups separately,
         * then this optimization in enum_dom_groups() will need
         * to be split out
         */
@@ -567,11 +531,12 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
                            const char *domain_name,
                            const char *name,
                            uint32_t flags,
+                           const char **pdom_name,
                            struct dom_sid *sid,
                            enum lsa_SidType *type)
 {
        return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
-                                        flags, sid, type);
+                                        flags, pdom_name, sid, type);
 }
 
 /* convert a domain SID to a user or group name - use rpc methods */
@@ -601,176 +566,11 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
                                           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
- * an rpc lookup sids call... R.I.P. */
-
-/* Lookup user information from a rid */
-static NTSTATUS query_user(struct winbindd_domain *domain, 
-                          TALLOC_CTX *mem_ctx, 
-                          const struct dom_sid *sid,
-                          struct wbint_userinfo *info)
-{
-       ADS_STRUCT *ads = NULL;
-       const char *attrs[] = { "*", NULL };
-       ADS_STATUS rc;
-       int count;
-       LDAPMessage *msg = NULL;
-       char *ldap_exp;
-       char *sidstr;
-       uint32_t group_rid;
-       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       struct netr_SamInfo3 *user = NULL;
-       gid_t gid = -1;
-       int ret;
-       char *full_name;
-
-       DEBUG(3,("ads: query_user\n"));
-
-       info->homedir = NULL;
-       info->shell = NULL;
-
-       /* 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,
-                             &info->homedir, &info->shell, &info->full_name, 
-                             &gid );
-               info->primary_gid = gid;
-
-               TALLOC_FREE(user);
-
-               if (info->full_name == NULL) {
-                       /* this might fail so we don't check the return code */
-                       wcache_query_user_fullname(domain,
-                                                  mem_ctx,
-                                                  sid,
-                                                  &info->full_name);
-               }
-
-               return NT_STATUS_OK;
-       }
-
-       if ( !winbindd_can_contact_domain(domain)) {
-               DEBUG(8,("query_user: No incoming trust from domain %s\n",
-                        domain->name));
-
-               /* We still need to generate some basic information
-                  about the user even if we cannot contact the 
-                  domain.  Most of this stuff we can deduce. */
-
-               sid_copy( &info->user_sid, sid );
-
-               /* Assume "Domain Users" for the primary group */
-
-               sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
-
-               /* Try to fill in what the nss_info backend can do */
-
-               nss_get_info_cached( domain, sid, mem_ctx,
-                             &info->homedir, &info->shell, &info->full_name, 
-                             &gid);
-               info->primary_gid = gid;
-
-               return NT_STATUS_OK;
-       }
-
-       /* no cache...do the query */
-
-       if ( (ads = ads_cached_connection(domain)) == NULL ) {
-               domain->last_status = NT_STATUS_SERVER_DISABLED;
-               return NT_STATUS_SERVER_DISABLED;
-       }
-
-       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
-
-       ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
-       TALLOC_FREE(sidstr);
-       if (ret == -1) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
-       SAFE_FREE(ldap_exp);
-       if (!ADS_ERR_OK(rc)) {
-               DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
-                        sid_string_dbg(sid), ads_errstr(rc)));
-               return ads_ntstatus(rc);
-       } else if (!msg) {
-               DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
-                        sid_string_dbg(sid)));
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       count = ads_count_replies(ads, msg);
-       if (count != 1) {
-               DEBUG(1,("query_user(sid=%s): Not found\n",
-                        sid_string_dbg(sid)));
-               ads_msgfree(ads, msg);
-               return NT_STATUS_NO_SUCH_USER;
-       }
-
-       info->acct_name = ads_pull_username(ads, mem_ctx, msg);
-
-       if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
-               DEBUG(1,("No primary group for %s !?\n",
-                        sid_string_dbg(sid)));
-               ads_msgfree(ads, msg);
-               return NT_STATUS_NO_SUCH_USER;
-       }
-       sid_copy(&info->user_sid, sid);
-       sid_compose(&info->group_sid, &domain->sid, group_rid);
-
-       /*
-        * We have to fetch the "name" attribute before doing the
-        * nss_get_info_cached call. nss_get_info_cached might destroy
-        * the ads struct, potentially invalidating the ldap message.
-        */
-       full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
-       if (full_name == NULL) {
-               full_name = ads_pull_string(ads, mem_ctx, msg, "name");
-       }
-
-       ads_msgfree(ads, msg);
-       msg = NULL;
-
-       status = nss_get_info_cached( domain, sid, mem_ctx,
-                     &info->homedir, &info->shell, &info->full_name, 
-                     &gid);
-       info->primary_gid = gid;
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("nss_get_info_cached failed: %s\n",
-                         nt_errstr(status)));
-               return status;
-       }
-
-       if (info->full_name == NULL) {
-               info->full_name = full_name;
-       } else {
-               TALLOC_FREE(full_name);
-       }
-
-       status = NT_STATUS_OK;
-
-       DEBUG(3,("ads query_user gave %s\n", info->acct_name));
-       return NT_STATUS_OK;
-}
-
 /* Lookup groups a user is a member of - alternate method, for when
    tokenGroups are not available. */
 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
                                         TALLOC_CTX *mem_ctx,
-                                        const char *user_dn, 
+                                        const char *user_dn,
                                         struct dom_sid *primary_group,
                                         uint32_t *p_num_groups, struct dom_sid **user_sids)
 {
@@ -780,7 +580,7 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
        LDAPMessage *res = NULL;
        LDAPMessage *msg = NULL;
        char *ldap_exp;
-       ADS_STRUCT *ads;
+       ADS_STRUCT *ads = NULL;
        const char *group_attrs[] = {"objectSid", NULL};
        char *escaped_dn;
        uint32_t num_groups = 0;
@@ -789,13 +589,12 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
 
        if ( !winbindd_can_contact_domain( domain ) ) {
                DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
-                         domain->name));               
+                         domain->name));
                return NT_STATUS_OK;
        }
 
-       ads = ads_cached_connection(domain);
-
-       if (!ads) {
+       rc = ads_cached_connection(domain, &ads);
+       if (!ADS_ERR_OK(rc)) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                goto done;
        }
@@ -806,9 +605,9 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
        }
 
        ldap_exp = talloc_asprintf(mem_ctx,
-               "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
+               "(&(member=%s)(objectCategory=group)"
+               "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))",
                escaped_dn,
-               ADS_LDAP_MATCHING_RULE_BIT_AND,
                GROUP_TYPE_SECURITY_ENABLED);
        if (!ldap_exp) {
                DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
@@ -871,7 +670,7 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
 
        DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
 done:
-       if (res) 
+       if (res)
                ads_msgfree(ads, res);
 
        return status;
@@ -888,11 +687,11 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
 {
        ADS_STATUS rc;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       ADS_STRUCT *ads;
+       ADS_STRUCT *ads = NULL;
        const char *attrs[] = {"memberOf", NULL};
        uint32_t num_groups = 0;
        struct dom_sid *group_sids = NULL;
-       int i;
+       size_t i;
        char **strings = NULL;
        size_t num_strings = 0, num_sids = 0;
 
@@ -905,9 +704,8 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
                return NT_STATUS_OK;
        }
 
-       ads = ads_cached_connection(domain);
-
-       if (!ads) {
+       rc = ads_cached_connection(domain, &ads);
+       if (!ADS_ERR_OK(rc)) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                return NT_STATUS_UNSUCCESSFUL;
        }
@@ -1009,11 +807,12 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        uint32_t primary_group_rid;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        uint32_t num_groups = 0;
+       struct dom_sid_buf buf;
 
        DEBUG(3,("ads: lookup_usergroups\n"));
        *p_num_groups = 0;
 
-       status = lookup_usergroups_cached(domain, mem_ctx, sid, 
+       status = lookup_usergroups_cached(mem_ctx, sid,
                                          p_num_groups, user_sids);
        if (NT_STATUS_IS_OK(status)) {
                return NT_STATUS_OK;
@@ -1028,9 +827,8 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                return NT_STATUS_SYNCHRONIZATION_REQUIRED;
        }
 
-       ads = ads_cached_connection(domain);
-
-       if (!ads) {
+       rc = ads_cached_connection(domain, &ads);
+       if (!ADS_ERR_OK(rc)) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                status = NT_STATUS_SERVER_DISABLED;
                goto done;
@@ -1041,7 +839,9 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        if (!ADS_ERR_OK(rc)) {
                status = ads_ntstatus(rc);
                DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
-                         "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
+                         "%s\n",
+                         dom_sid_str_buf(sid, &buf),
+                         ads_errstr(rc)));
                goto done;
        }
 
@@ -1049,14 +849,15 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        if (count != 1) {
                status = NT_STATUS_UNSUCCESSFUL;
                DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
-                        "invalid number of results (count=%d)\n", 
-                        sid_string_dbg(sid), count));
+                        "invalid number of results (count=%d)\n",
+                        dom_sid_str_buf(sid, &buf),
+                        count));
                goto done;
        }
 
        if (!msg) {
-               DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
-                        sid_string_dbg(sid)));
+               DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
+                        dom_sid_str_buf(sid, &buf)));
                status = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
@@ -1068,8 +869,9 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        }
 
        if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
-               DEBUG(1,("%s: No primary group for sid=%s !?\n", 
-                        domain->name, sid_string_dbg(sid)));
+               DEBUG(1,("%s: No primary group for sid=%s !?\n",
+                        domain->name,
+                        dom_sid_str_buf(sid, &buf)));
                goto done;
        }
 
@@ -1077,7 +879,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
 
        count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
 
-       /* there must always be at least one group in the token, 
+       /* there must always be at least one group in the token,
           unless we are talking to a buggy Win2k server */
 
        /* actually this only happens when the machine account has no read
@@ -1101,7 +903,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                /* lookup what groups this user is a member of by DN search on
                 * "member" */
 
-               status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
+               status = lookup_usergroups_member(domain, mem_ctx, user_dn,
                                                  &primary_group,
                                                  &num_groups, user_sids);
                *p_num_groups = num_groups;
@@ -1135,7 +937,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
 
        DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
-                sid_string_dbg(sid)));
+                dom_sid_str_buf(sid, &buf)));
 done:
        TALLOC_FREE(user_dn);
        ads_msgfree(ads, msg);
@@ -1153,7 +955,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
 }
 
 static NTSTATUS add_primary_group_members(
-       ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
+       ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, const char *domname,
        char ***all_members, size_t *num_all_members)
 {
        char *filter;
@@ -1165,10 +967,13 @@ static NTSTATUS add_primary_group_members(
        char **members;
        size_t num_members;
        ads_control args;
+       bool all_groupmem = idmap_config_bool(domname, "all_groupmem", false);
 
        filter = talloc_asprintf(
-               mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
-               (unsigned)rid);
+               mem_ctx,
+               "(&(objectCategory=user)(primaryGroupID=%u)%s)",
+               (unsigned)rid,
+               all_groupmem ? "" : "(uidNumber=*)(!(uidNumber=0))");
        if (filter == NULL) {
                goto done;
        }
@@ -1249,7 +1054,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        char *sidbinstr;
        char **members = NULL;
-       int i;
+       size_t i;
        size_t num_members = 0;
        ads_control args;
        struct dom_sid *sid_mem_nocache = NULL;
@@ -1259,9 +1064,10 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        uint32_t num_nocache = 0;
        TALLOC_CTX *tmp_ctx = NULL;
        uint32_t rid;
+       struct dom_sid_buf buf;
 
        DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
-                 sid_string_dbg(group_sid)));
+                 dom_sid_str_buf(group_sid, &buf)));
 
        *num_names = 0;
 
@@ -1284,9 +1090,8 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                return NT_STATUS_OK;
        }
 
-       ads = ads_cached_connection(domain);
-
-       if (!ads) {
+       rc = ads_cached_connection(domain, &ads);
+       if (!ADS_ERR_OK(rc)) {
                domain->last_status = NT_STATUS_SERVER_DISABLED;
                goto done;
        }
@@ -1320,7 +1125,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 
        DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
 
-       status = add_primary_group_members(ads, mem_ctx, rid,
+       status = add_primary_group_members(ads, mem_ctx, rid, domain->name,
                                           &members, &num_members);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
@@ -1387,7 +1192,8 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                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)));
+                                 "cache\n",
+                                 dom_sid_str_buf(&sid, &buf)));
                        sid_copy(&(*sid_mem)[*num_names], &sid);
                        (*names)[*num_names] = fill_domain_username_talloc(
                                                        *names,
@@ -1400,7 +1206,8 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                }
                else {
                        DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
-                                  "cache\n", sid_string_dbg(&sid)));
+                                  "cache\n",
+                                  dom_sid_str_buf(&sid, &buf)));
                        sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
                        num_nocache++;
                }
@@ -1463,7 +1270,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                        DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
                                   "not map any SIDs at all.\n"));
                        /* Don't handle this as an error here.
-                        * There is nothing left to do with respect to the 
+                        * There is nothing left to do with respect to the
                         * overall result... */
                }
                else if (!NT_STATUS_IS_OK(status)) {
@@ -1476,7 +1283,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 
        status = NT_STATUS_OK;
        DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
-                sid_string_dbg(group_sid)));
+                dom_sid_str_buf(group_sid, &buf)));
 
 done:
 
@@ -1485,45 +1292,29 @@ done:
        return status;
 }
 
-/* find the sequence number for a domain */
-static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
+static NTSTATUS lookup_aliasmem(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               const struct dom_sid *sid,
+                               enum lsa_SidType type,
+                               uint32_t *num_sids,
+                               struct dom_sid **sids)
 {
-       ADS_STRUCT *ads = NULL;
-       ADS_STATUS rc;
-
-       DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
-
-       if ( !winbindd_can_contact_domain( domain ) ) {
-               DEBUG(10,("sequence: No incoming trust for domain %s\n",
-                         domain->name));
-               *seq = time(NULL);              
-               return NT_STATUS_OK;
-       }
-
-       *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) {
-                       ads = (ADS_STRUCT *)domain->private_data;
-                       ads->is_mine = True;
-                       ads_destroy(&ads);
-                       ads_kdestroy(WINBIND_CCACHE_NAME);
-                       domain->private_data = NULL;
-               }
-       }
-       return ads_ntstatus(rc);
+       char **names = NULL;
+       uint32_t *name_types = NULL;
+       struct dom_sid_buf buf;
+
+       DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
+                 domain->name,
+                 dom_sid_str_buf(sid, &buf));
+       /* Search for alias and group membership uses the same LDAP command. */
+       return lookup_groupmem(domain,
+                              mem_ctx,
+                              sid,
+                              type,
+                              num_sids,
+                              sids,
+                              &names,
+                              &name_types);
 }
 
 /* find the lockout policy of a domain - use rpc methods */
@@ -1549,10 +1340,9 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
 {
        NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
        WERROR werr;
-       int                     i;
+       uint32_t                i;
        uint32_t                flags;
        struct rpc_pipe_client *cli;
-       int ret_count;
        struct dcerpc_binding_handle *b;
 
        DEBUG(3,("ads: trusted_domains\n"));
@@ -1569,13 +1359,13 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                        NETR_TRUST_FLAG_IN_FOREST;
        } else {
                flags = NETR_TRUST_FLAG_IN_FOREST;
-       }       
+       }
 
        result = cm_connect_netlogon(domain, &cli);
 
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(5, ("trusted_domains: Could not open a connection to %s "
-                         "for PIPE_NETLOGON (%s)\n", 
+                         "for PIPE_NETLOGON (%s)\n",
                          domain->name, nt_errstr(result)));
                return NT_STATUS_UNSUCCESSFUL;
        }
@@ -1600,7 +1390,6 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
 
        /* Copy across names and sids */
 
-       ret_count = 0;
        for (i = 0; i < trusts->count; i++) {
                struct netr_DomainTrust *trust = &trusts->array[i];
                struct winbindd_domain d;
@@ -1615,7 +1404,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                 */
 
                if ((trust->trust_attributes
-                    == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
+                    & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
                    !domain->primary )
                {
                        DEBUG(10,("trusted_domains: Skipping external trusted "
@@ -1647,7 +1436,6 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                        d.domain_trust_attribs = trust->trust_attributes;
 
                        wcache_tdc_add_domain( &d );
-                       ret_count++;
                } else if (domain_is_forest_root(domain)) {
                        /* Check if we already have this record. If
                         * we are following our forest root that is not
@@ -1669,7 +1457,6 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                        trust->trust_attributes;
 
                                wcache_tdc_add_domain( &d );
-                               ret_count++;
                        }
                        TALLOC_FREE(exist);
                } else {
@@ -1701,8 +1488,15 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                        }
                        TALLOC_FREE(parent);
 
+                       /*
+                        * We need to pass the modified properties
+                        * to the caller.
+                        */
+                       trust->trust_flags = d.domain_flags;
+                       trust->trust_type = d.domain_type;
+                       trust->trust_attributes = d.domain_trust_attribs;
+
                        wcache_tdc_add_domain( &d );
-                       ret_count++;
                }
        }
        return result;
@@ -1717,11 +1511,10 @@ struct winbindd_methods ads_methods = {
        name_to_sid,
        sid_to_name,
        rids_to_names,
-       query_user,
        lookup_usergroups,
        lookup_useraliases,
        lookup_groupmem,
-       sequence_number,
+       lookup_aliasmem,
        lockout_policy,
        password_policy,
        trusted_domains,