s3-pdb: Make ADS-type backends updates secrets.tdb.
[ira/wip.git] / source3 / passdb / pdb_ads.c
index 8d7c215986702f2e74fba097a201c27f95953490..cd7781a1afa4c6e8607853ff6c76bcd5eb3bd7d7 100644 (file)
 */
 
 #include "includes.h"
+#include "passdb.h"
+#include "tldap.h"
+#include "tldap_util.h"
+#include "../libds/common/flags.h"
+#include "secrets.h"
+#include "../librpc/gen_ndr/samr.h"
+#include "../libcli/ldap/ldap_ndr.h"
+#include "../libcli/security/security.h"
+#include "../libds/common/flag_mapping.h"
 
 struct pdb_ads_state {
+       struct sockaddr_un socket_address;
        struct tldap_context *ld;
        struct dom_sid domainsid;
+       struct GUID domainguid;
        char *domaindn;
        char *configdn;
        char *netbiosname;
 };
 
-static NTSTATUS pdb_ads_getsampwsid(struct pdb_methods *m,
-                                   struct samu *sam_acct,
-                                   const DOM_SID *sid);
+struct pdb_ads_samu_private {
+       char *dn;
+       struct tldap_message *ldapmsg;
+};
+
 static bool pdb_ads_gid_to_sid(struct pdb_methods *m, gid_t gid,
-                              DOM_SID *sid);
-static bool pdb_ads_dnblob2sid(struct tldap_context *ld, DATA_BLOB *dnblob,
+                              struct dom_sid *sid);
+static bool pdb_ads_dnblob2sid(struct pdb_ads_state *state, DATA_BLOB *dnblob,
                               struct dom_sid *psid);
 static NTSTATUS pdb_ads_sid2dn(struct pdb_ads_state *state,
                               const struct dom_sid *sid,
                               TALLOC_CTX *mem_ctx, char **pdn);
+static struct tldap_context *pdb_ads_ld(struct pdb_ads_state *state);
+static int pdb_ads_search_fmt(struct pdb_ads_state *state, const char *base,
+                             int scope, const char *attrs[], int num_attrs,
+                             int attrsonly,
+                             TALLOC_CTX *mem_ctx, struct tldap_message ***res,
+                             const char *fmt, ...);
+static NTSTATUS pdb_ads_getsamupriv(struct pdb_ads_state *state,
+                                   const char *filter,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct pdb_ads_samu_private **presult);
 
 static bool pdb_ads_pull_time(struct tldap_message *msg, const char *attr,
                              time_t *ptime)
@@ -46,7 +69,7 @@ static bool pdb_ads_pull_time(struct tldap_message *msg, const char *attr,
        if (!tldap_pull_uint64(msg, attr, &tmp)) {
                return false;
        }
-       *ptime = uint64s_nt_time_to_unix_abs(&tmp);
+       *ptime = nt_time_to_unix(tmp);
        return true;
 }
 
@@ -57,42 +80,73 @@ static gid_t pdb_ads_sid2gid(const struct dom_sid *sid)
        return rid;
 }
 
-struct pdb_ads_samu_private {
-       char *dn;
-       struct tldap_message *ldapmsg;
-};
+static char *pdb_ads_domaindn2dns(TALLOC_CTX *mem_ctx, char *dn)
+{
+       char *result, *p;
+
+       result = talloc_string_sub2(mem_ctx, dn, "DC=", "", false, false,
+                                   true);
+       if (result == NULL) {
+               return NULL;
+       }
 
-static struct samu *pdb_ads_init_guest(TALLOC_CTX *mem_ctx,
-                                      struct pdb_methods *m)
+       while ((p = strchr_m(result, ',')) != NULL) {
+               *p = '.';
+       }
+
+       return result;
+}
+
+static struct pdb_domain_info *pdb_ads_get_domain_info(
+       struct pdb_methods *m, TALLOC_CTX *mem_ctx)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
-       struct dom_sid guest_sid;
-       struct samu *guest;
-       NTSTATUS status;
-
-       sid_compose(&guest_sid, &state->domainsid, DOMAIN_USER_RID_GUEST);
+       struct pdb_domain_info *info;
+       struct tldap_message *rootdse;
+       char *tmp;
 
-       guest = samu_new(mem_ctx);
-       if (guest == NULL) {
+       info = talloc(mem_ctx, struct pdb_domain_info);
+       if (info == NULL) {
                return NULL;
        }
+       info->name = talloc_strdup(info, state->netbiosname);
+       if (info->name == NULL) {
+               goto fail;
+       }
+       info->dns_domain = pdb_ads_domaindn2dns(info, state->domaindn);
+       if (info->dns_domain == NULL) {
+               goto fail;
+       }
 
-       status = pdb_ads_getsampwsid(m, guest, &guest_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(10, ("Could not init guest account: %s\n",
-                          nt_errstr(status)));
-               TALLOC_FREE(guest);
-               return NULL;
+       rootdse = tldap_rootdse(state->ld);
+       tmp = tldap_talloc_single_attribute(rootdse, "rootDomainNamingContext",
+                                           talloc_tos());
+       if (tmp == NULL) {
+               goto fail;
+       }
+       info->dns_forest = pdb_ads_domaindn2dns(info, tmp);
+       TALLOC_FREE(tmp);
+       if (info->dns_forest == NULL) {
+               goto fail;
        }
-       return guest;
+       info->sid = state->domainsid;
+       info->guid = state->domainguid;
+       return info;
+
+fail:
+       TALLOC_FREE(info);
+       return NULL;
 }
 
 static struct pdb_ads_samu_private *pdb_ads_get_samu_private(
        struct pdb_methods *m, struct samu *sam)
 {
+       struct pdb_ads_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_ads_state);
        struct pdb_ads_samu_private *result;
-       uint32_t rid;
+       char *sidstr, *filter;
+       NTSTATUS status;
 
        result = (struct pdb_ads_samu_private *)
                pdb_get_backend_private_data(sam, m);
@@ -102,56 +156,43 @@ static struct pdb_ads_samu_private *pdb_ads_get_samu_private(
                        result, struct pdb_ads_samu_private);
        }
 
-       /*
-        * This is now a weirdness of the passdb API. For the guest user we
-        * are not asked first.
-        */
-       sid_peek_rid(pdb_get_user_sid(sam), &rid);
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), pdb_get_user_sid(sam));
+       if (sidstr == NULL) {
+               return NULL;
+       }
 
-       if (rid == DOMAIN_USER_RID_GUEST) {
-               struct samu *guest = pdb_ads_init_guest(talloc_tos(), m);
+       filter = talloc_asprintf(
+               talloc_tos(), "(&(objectsid=%s)(objectclass=user))", sidstr);
+       TALLOC_FREE(sidstr);
+       if (filter == NULL) {
+               return NULL;
+       }
 
-               if (guest == NULL) {
-                       return NULL;
-               }
-               result = talloc_get_type_abort(
-                       pdb_get_backend_private_data(guest, m),
-                       struct pdb_ads_samu_private);
-               pdb_set_backend_private_data(
-                       sam, talloc_move(sam, &result), NULL, m, PDB_SET);
-               TALLOC_FREE(guest);
-               return talloc_get_type_abort(
-                       pdb_get_backend_private_data(sam, m),
-                       struct pdb_ads_samu_private);
+       status = pdb_ads_getsamupriv(state, filter, sam, &result);
+       TALLOC_FREE(filter);
+       if (!NT_STATUS_IS_OK(status)) {
+               return NULL;
        }
 
-       return NULL;
+       return result;
 }
 
-static NTSTATUS pdb_ads_init_sam_from_ads(struct pdb_methods *m,
-                                         struct samu *sam,
-                                         struct tldap_message *entry)
+static NTSTATUS pdb_ads_init_sam_from_priv(struct pdb_methods *m,
+                                          struct samu *sam,
+                                          struct pdb_ads_samu_private *priv)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
        TALLOC_CTX *frame = talloc_stackframe();
-       struct pdb_ads_samu_private *priv;
        NTSTATUS status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+       struct tldap_message *entry = priv->ldapmsg;
        char *str;
        time_t tmp_time;
        struct dom_sid sid;
        uint64_t n;
+       uint32_t i;
        DATA_BLOB blob;
 
-       priv = talloc(sam, struct pdb_ads_samu_private);
-       if (priv == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       if (!tldap_entry_dn(entry, &priv->dn)) {
-               TALLOC_FREE(priv);
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
        str = tldap_talloc_single_attribute(entry, "samAccountName", sam);
        if (str == NULL) {
                DEBUG(10, ("no samAccountName\n"));
@@ -169,7 +210,7 @@ static NTSTATUS pdb_ads_init_sam_from_ads(struct pdb_methods *m,
                pdb_set_pass_last_set_time(sam, tmp_time, PDB_SET);
        }
        if (pdb_ads_pull_time(entry, "accountExpires", &tmp_time)) {
-               pdb_set_pass_last_set_time(sam, tmp_time, PDB_SET);
+               pdb_set_kickoff_time(sam, tmp_time, PDB_SET);
        }
 
        str = tldap_talloc_single_attribute(entry, "displayName",
@@ -206,6 +247,30 @@ static NTSTATUS pdb_ads_init_sam_from_ads(struct pdb_methods *m,
                pdb_set_profile_path(sam, str, PDB_SET);
        }
 
+       str = tldap_talloc_single_attribute(entry, "comment",
+                                           talloc_tos());
+       if (str != NULL) {
+               pdb_set_comment(sam, str, PDB_SET);
+       }
+
+       str = tldap_talloc_single_attribute(entry, "description",
+                                           talloc_tos());
+       if (str != NULL) {
+               pdb_set_acct_desc(sam, str, PDB_SET);
+       }
+
+       str = tldap_talloc_single_attribute(entry, "userWorkstations",
+                                           talloc_tos());
+       if (str != NULL) {
+               pdb_set_workstations(sam, str, PDB_SET);
+       }
+
+       str = tldap_talloc_single_attribute(entry, "userParameters",
+                                           talloc_tos());
+       if (str != NULL) {
+               pdb_set_munged_dial(sam, str, PDB_SET);
+       }
+
        if (!tldap_pull_binsid(entry, "objectSid", &sid)) {
                DEBUG(10, ("Could not pull SID\n"));
                goto fail;
@@ -216,7 +281,7 @@ static NTSTATUS pdb_ads_init_sam_from_ads(struct pdb_methods *m,
                DEBUG(10, ("Could not pull userAccountControl\n"));
                goto fail;
        }
-       pdb_set_acct_ctrl(sam, ads_uf2acb(n), PDB_SET);
+       pdb_set_acct_ctrl(sam, ds_uf2acb(n), PDB_SET);
 
        if (tldap_get_single_valueblob(entry, "unicodePwd", &blob)) {
                if (blob.length != NT_HASH_LEN) {
@@ -242,8 +307,31 @@ static NTSTATUS pdb_ads_init_sam_from_ads(struct pdb_methods *m,
 
        }
 
-       priv->ldapmsg = talloc_move(priv, &entry);
-       pdb_set_backend_private_data(sam, priv, NULL, m, PDB_SET);
+       if (tldap_pull_uint32(entry, "countryCode", &i)) {
+               pdb_set_country_code(sam, i, PDB_SET);
+       }
+
+       if (tldap_pull_uint32(entry, "codePage", &i)) {
+               pdb_set_code_page(sam, i, PDB_SET);
+       }
+
+       if (tldap_get_single_valueblob(entry, "logonHours", &blob)) {
+
+               if (blob.length > MAX_HOURS_LEN) {
+                       status = NT_STATUS_INVALID_PARAMETER;
+                       goto fail;
+               }
+               pdb_set_logon_divs(sam, blob.length * 8, PDB_SET);
+               pdb_set_hours_len(sam, blob.length, PDB_SET);
+               pdb_set_hours(sam, blob.data, blob.length, PDB_SET);
+
+       } else {
+               uint8_t hours[21];
+               pdb_set_logon_divs(sam, sizeof(hours)/8, PDB_SET);
+               pdb_set_hours_len(sam, sizeof(hours), PDB_SET);
+               memset(hours, 0xff, sizeof(hours));
+               pdb_set_hours(sam, hours, sizeof(hours), PDB_SET);
+       }
 
        status = NT_STATUS_OK;
 fail:
@@ -251,55 +339,129 @@ fail:
        return status;
 }
 
+static bool pdb_ads_make_time_mod(struct tldap_message *existing,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct tldap_mod **pmods, int *pnum_mods,
+                                 const char *attrib, time_t t)
+{
+       uint64_t nt_time;
+
+       unix_to_nt_time(&nt_time, t);
+
+       return tldap_make_mod_fmt(
+               existing, mem_ctx, pmods, pnum_mods, attrib,
+               "%llu", nt_time);
+}
+
 static bool pdb_ads_init_ads_from_sam(struct pdb_ads_state *state,
                                      struct tldap_message *existing,
                                      TALLOC_CTX *mem_ctx,
-                                     int *pnum_mods, struct tldap_mod **pmods,
+                                     struct tldap_mod **pmods, int *pnum_mods,
                                      struct samu *sam)
 {
        bool ret = true;
+       DATA_BLOB blob;
+       const char *pw;
 
        /* TODO: All fields :-) */
 
        ret &= tldap_make_mod_fmt(
-               existing, mem_ctx, pnum_mods, pmods, "displayName",
+               existing, mem_ctx, pmods, pnum_mods, "displayName",
                "%s", pdb_get_fullname(sam));
 
-       ret &= tldap_make_mod_blob(
-               existing, mem_ctx, pnum_mods, pmods, "unicodePwd",
-               data_blob_const(pdb_get_nt_passwd(sam), NT_HASH_LEN));
+       pw = pdb_get_plaintext_passwd(sam);
 
-       ret &= tldap_make_mod_blob(
-               existing, mem_ctx, pnum_mods, pmods, "dBCSPwd",
-               data_blob_const(pdb_get_lanman_passwd(sam), NT_HASH_LEN));
+       /*
+        * If we have the plain text pw, this is probably about to be
+        * set. Is this true always?
+        */
+       if (pw != NULL) {
+               char *pw_quote;
+               uint8_t *pw_utf16;
+               size_t pw_utf16_len;
+
+               pw_quote = talloc_asprintf(talloc_tos(), "\"%s\"", pw);
+               if (pw_quote == NULL) {
+                       ret = false;
+                       goto fail;
+               }
+
+               ret &= convert_string_talloc(talloc_tos(),
+                                            CH_UNIX, CH_UTF16LE,
+                                            pw_quote, strlen(pw_quote),
+                                            &pw_utf16, &pw_utf16_len);
+               if (!ret) {
+                       goto fail;
+               }
+               blob = data_blob_const(pw_utf16, pw_utf16_len);
+
+               ret &= tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods,
+                                          TLDAP_MOD_REPLACE,
+                                          "unicodePwd", &blob, 1);
+               TALLOC_FREE(pw_utf16);
+               TALLOC_FREE(pw_quote);
+       }
 
        ret &= tldap_make_mod_fmt(
-               existing, mem_ctx, pnum_mods, pmods, "userAccountControl",
-               "%d", ads_acb2uf(pdb_get_acct_ctrl(sam)));
+               existing, mem_ctx, pmods, pnum_mods, "userAccountControl",
+               "%d", ds_acb2uf(pdb_get_acct_ctrl(sam)));
 
        ret &= tldap_make_mod_fmt(
-               existing, mem_ctx, pnum_mods, pmods, "homeDirectory",
+               existing, mem_ctx, pmods, pnum_mods, "homeDirectory",
                "%s", pdb_get_homedir(sam));
 
        ret &= tldap_make_mod_fmt(
-               existing, mem_ctx, pnum_mods, pmods, "homeDrive",
+               existing, mem_ctx, pmods, pnum_mods, "homeDrive",
                "%s", pdb_get_dir_drive(sam));
 
        ret &= tldap_make_mod_fmt(
-               existing, mem_ctx, pnum_mods, pmods, "scriptPath",
+               existing, mem_ctx, pmods, pnum_mods, "scriptPath",
                "%s", pdb_get_logon_script(sam));
 
        ret &= tldap_make_mod_fmt(
-               existing, mem_ctx, pnum_mods, pmods, "profilePath",
+               existing, mem_ctx, pmods, pnum_mods, "profilePath",
                "%s", pdb_get_profile_path(sam));
 
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pmods, pnum_mods, "comment",
+               "%s", pdb_get_comment(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pmods, pnum_mods, "description",
+               "%s", pdb_get_acct_desc(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pmods, pnum_mods, "userWorkstations",
+               "%s", pdb_get_workstations(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pmods, pnum_mods, "userParameters",
+               "%s", pdb_get_munged_dial(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pmods, pnum_mods, "countryCode",
+               "%i", (int)pdb_get_country_code(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pmods, pnum_mods, "codePage",
+               "%i", (int)pdb_get_code_page(sam));
+
+       ret &= pdb_ads_make_time_mod(
+               existing, mem_ctx, pmods, pnum_mods, "accountExpires",
+               (int)pdb_get_kickoff_time(sam));
+
+       ret &= tldap_make_mod_blob(
+               existing, mem_ctx, pmods, pnum_mods, "logonHours",
+               data_blob_const(pdb_get_hours(sam), pdb_get_hours_len(sam)));
+
+fail:
        return ret;
 }
 
-static NTSTATUS pdb_ads_getsampwfilter(struct pdb_methods *m,
-                                      struct pdb_ads_state *state,
-                                      struct samu *sam_acct,
-                                      const char *filter)
+static NTSTATUS pdb_ads_getsamupriv(struct pdb_ads_state *state,
+                                   const char *filter,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct pdb_ads_samu_private **presult)
 {
        const char * attrs[] = {
                "lastLogon", "lastLogoff", "pwdLastSet", "accountExpires",
@@ -311,23 +473,66 @@ static NTSTATUS pdb_ads_getsampwfilter(struct pdb_methods *m,
                "unicodePwd", "dBCSPwd" };
        struct tldap_message **users;
        int rc, count;
+       struct pdb_ads_samu_private *result;
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
-                             &users, "%s", filter);
+       result = talloc(mem_ctx, struct pdb_ads_samu_private);
+       if (result == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, result,
+                               &users, "%s", filter);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
+               TALLOC_FREE(result);
                return NT_STATUS_LDAP(rc);
        }
 
        count = talloc_array_length(users);
        if (count != 1) {
                DEBUG(10, ("Expected 1 user, got %d\n", count));
+               TALLOC_FREE(result);
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       result->ldapmsg = users[0];
+       if (!tldap_entry_dn(result->ldapmsg, &result->dn)) {
+               DEBUG(10, ("Could not extract dn\n"));
+               TALLOC_FREE(result);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       return pdb_ads_init_sam_from_ads(m, sam_acct, users[0]);
+       *presult = result;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_ads_getsampwfilter(struct pdb_methods *m,
+                                      struct pdb_ads_state *state,
+                                      struct samu *sam_acct,
+                                      const char *filter)
+{
+       struct pdb_ads_samu_private *priv;
+       NTSTATUS status;
+
+       status = pdb_ads_getsamupriv(state, filter, sam_acct, &priv);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("pdb_ads_getsamupriv failed: %s\n",
+                          nt_errstr(status)));
+               return status;
+       }
+
+       status = pdb_ads_init_sam_from_priv(m, sam_acct, priv);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("pdb_ads_init_sam_from_priv failed: %s\n",
+                          nt_errstr(status)));
+               TALLOC_FREE(priv);
+               return status;
+       }
+
+       pdb_set_backend_private_data(sam_acct, priv, NULL, m, PDB_SET);
+       return NT_STATUS_OK;
 }
 
 static NTSTATUS pdb_ads_getsampwnam(struct pdb_methods *m,
@@ -348,13 +553,13 @@ static NTSTATUS pdb_ads_getsampwnam(struct pdb_methods *m,
 
 static NTSTATUS pdb_ads_getsampwsid(struct pdb_methods *m,
                                    struct samu *sam_acct,
-                                   const DOM_SID *sid)
+                                   const struct dom_sid *sid)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
        char *sidstr, *filter;
 
-       sidstr = sid_binstring(talloc_tos(), sid);
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
        NT_STATUS_HAVE_NO_MEMORY(sidstr);
 
        filter = talloc_asprintf(
@@ -372,6 +577,7 @@ static NTSTATUS pdb_ads_create_user(struct pdb_methods *m,
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
        const char *attrs[1] = { "objectSid" };
        struct tldap_mod *mods = NULL;
        int num_mods = 0;
@@ -387,33 +593,40 @@ static NTSTATUS pdb_ads_create_user(struct pdb_methods *m,
                return NT_STATUS_NO_MEMORY;
        }
 
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
        /* TODO: Create machines etc */
 
        ok = true;
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "objectClass", "user");
+               NULL, talloc_tos(), &mods, &num_mods, "objectClass", "user");
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "samAccountName", "%s",
+               NULL, talloc_tos(), &mods, &num_mods, "samAccountName", "%s",
                name);
        if (!ok) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       rc = tldap_add(state->ld, dn, num_mods, mods, NULL, NULL);
+
+       rc = tldap_add(ld, dn, mods, num_mods, NULL, 0, NULL, 0);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_add failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), ld, rc)));
                TALLOC_FREE(dn);
                return NT_STATUS_LDAP(rc);
        }
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &user,
-                            "(&(objectclass=user)(samaccountname=%s))",
-                            name);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &user,
+                               "(&(objectclass=user)(samaccountname=%s))",
+                               name);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("Could not find just created user %s: %s\n",
-                          name, tldap_errstr(debug_ctx(), state->ld, rc)));
+                          name, tldap_errstr(talloc_tos(), state->ld, rc)));
                TALLOC_FREE(dn);
                return NT_STATUS_LDAP(rc);
        }
@@ -444,20 +657,26 @@ static NTSTATUS pdb_ads_delete_user(struct pdb_methods *m,
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
        NTSTATUS status;
+       struct tldap_context *ld;
        char *dn;
        int rc;
 
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
        status = pdb_ads_sid2dn(state, pdb_get_user_sid(sam), talloc_tos(),
                                &dn);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       rc = tldap_delete(state->ld, dn, NULL, NULL);
+       rc = tldap_delete(ld, dn, NULL, 0, NULL, 0);
        TALLOC_FREE(dn);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_delete for %s failed: %s\n", dn,
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
        return NT_STATUS_OK;
@@ -475,11 +694,17 @@ static NTSTATUS pdb_ads_update_sam_account(struct pdb_methods *m,
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
        struct pdb_ads_samu_private *priv = pdb_ads_get_samu_private(m, sam);
+       struct tldap_context *ld;
        struct tldap_mod *mods = NULL;
        int rc, num_mods = 0;
 
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
        if (!pdb_ads_init_ads_from_sam(state, priv->ldapmsg, talloc_tos(),
-                                      &num_mods, &mods, sam)) {
+                                      &mods, &num_mods, sam)) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -488,15 +713,15 @@ static NTSTATUS pdb_ads_update_sam_account(struct pdb_methods *m,
                return NT_STATUS_OK;
        }
 
-       rc = tldap_modify(state->ld, priv->dn, num_mods, mods, NULL, NULL);
+       rc = tldap_modify(ld, priv->dn, mods, num_mods, NULL, 0,
+                         NULL, 0);
+       TALLOC_FREE(mods);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_modify for %s failed: %s\n", priv->dn,
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
 
-       TALLOC_FREE(mods);
-
        return NT_STATUS_OK;
 }
 
@@ -521,7 +746,9 @@ static NTSTATUS pdb_ads_update_login_attempts(struct pdb_methods *m,
 }
 
 static NTSTATUS pdb_ads_getgrfilter(struct pdb_methods *m, GROUP_MAP *map,
-                                   const char *filter)
+                                   const char *filter,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct tldap_message **pmsg)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
@@ -532,16 +759,16 @@ static NTSTATUS pdb_ads_getgrfilter(struct pdb_methods *m, GROUP_MAP *map,
        uint32_t grouptype;
        int rc;
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
-                             &group, "%s", filter);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &group, "%s", filter);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
        if (talloc_array_length(group) != 1) {
-               DEBUG(10, ("Expected 1 user, got %d\n",
+               DEBUG(10, ("Expected 1 group, got %d\n",
                           (int)talloc_array_length(group)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
@@ -571,24 +798,25 @@ static NTSTATUS pdb_ads_getgrfilter(struct pdb_methods *m, GROUP_MAP *map,
        if (str == NULL) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       fstrcpy(map->nt_name, str);
-       TALLOC_FREE(str);
+       map->nt_name = talloc_move(map, &str);
 
        str = tldap_talloc_single_attribute(group[0], "description",
                                            talloc_tos());
        if (str != NULL) {
-               fstrcpy(map->comment, str);
-               TALLOC_FREE(str);
+               map->comment = talloc_move(map, &str);
        } else {
-               map->comment[0] = '\0';
+               map->comment = talloc_strdup(map, "");
        }
 
+       if (pmsg != NULL) {
+               *pmsg = talloc_move(mem_ctx, &group[0]);
+       }
        TALLOC_FREE(group);
        return NT_STATUS_OK;
 }
 
 static NTSTATUS pdb_ads_getgrsid(struct pdb_methods *m, GROUP_MAP *map,
-                                DOM_SID sid)
+                                struct dom_sid sid)
 {
        char *filter;
        NTSTATUS status;
@@ -600,7 +828,7 @@ static NTSTATUS pdb_ads_getgrsid(struct pdb_methods *m, GROUP_MAP *map,
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = pdb_ads_getgrfilter(m, map, filter);
+       status = pdb_ads_getgrfilter(m, map, filter, NULL, NULL);
        TALLOC_FREE(filter);
        return status;
 }
@@ -626,7 +854,7 @@ static NTSTATUS pdb_ads_getgrnam(struct pdb_methods *m, GROUP_MAP *map,
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = pdb_ads_getgrfilter(m, map, filter);
+       status = pdb_ads_getgrfilter(m, map, filter, NULL, NULL);
        TALLOC_FREE(filter);
        return status;
 }
@@ -638,6 +866,7 @@ static NTSTATUS pdb_ads_create_dom_group(struct pdb_methods *m,
        TALLOC_CTX *frame = talloc_stackframe();
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
        const char *attrs[1] = { "objectSid" };
        int num_mods = 0;
        struct tldap_mod *mods = NULL;
@@ -647,6 +876,11 @@ static NTSTATUS pdb_ads_create_dom_group(struct pdb_methods *m,
        int rc;
        bool ok = true;
 
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
        dn = talloc_asprintf(talloc_tos(), "cn=%s,cn=users,%s", name,
                             state->domaindn);
        if (dn == NULL) {
@@ -655,12 +889,12 @@ static NTSTATUS pdb_ads_create_dom_group(struct pdb_methods *m,
        }
 
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "samAccountName", "%s",
+               NULL, talloc_tos(), &mods, &num_mods, "samAccountName", "%s",
                name);
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "objectClass", "group");
+               NULL, talloc_tos(), &mods, &num_mods, "objectClass", "group");
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "groupType",
+               NULL, talloc_tos(), &mods, &num_mods, "groupType",
                "%d", (int)GTYPE_SECURITY_GLOBAL_GROUP);
 
        if (!ok) {
@@ -668,21 +902,21 @@ static NTSTATUS pdb_ads_create_dom_group(struct pdb_methods *m,
                return NT_STATUS_NO_MEMORY;
        }
 
-       rc = tldap_add(state->ld, dn, num_mods, mods, NULL, NULL);
+       rc = tldap_add(ld, dn, mods, num_mods, NULL, 0, NULL, 0);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_add failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                TALLOC_FREE(frame);
                return NT_STATUS_LDAP(rc);
        }
 
-       rc = tldap_search_fmt(
-               state->ld, state->domaindn, TLDAP_SCOPE_SUB,
+       rc = pdb_ads_search_fmt(
+               state, state->domaindn, TLDAP_SCOPE_SUB,
                attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &alias,
                "(&(objectclass=group)(samaccountname=%s))", name);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("Could not find just created alias %s: %s\n",
-                          name, tldap_errstr(debug_ctx(), state->ld, rc)));
+                          name, tldap_errstr(talloc_tos(), state->ld, rc)));
                TALLOC_FREE(frame);
                return NT_STATUS_LDAP(rc);
        }
@@ -711,6 +945,7 @@ static NTSTATUS pdb_ads_delete_dom_group(struct pdb_methods *m,
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
        struct dom_sid sid;
        char *sidstr;
        struct tldap_message **msg;
@@ -719,17 +954,17 @@ static NTSTATUS pdb_ads_delete_dom_group(struct pdb_methods *m,
 
        sid_compose(&sid, &state->domainsid, rid);
 
-       sidstr = sid_binstring(talloc_tos(), &sid);
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), &sid);
        NT_STATUS_HAVE_NO_MEMORY(sidstr);
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             NULL, 0, 0, talloc_tos(), &msg,
-                             ("(&(objectSid=%s)(objectClass=group))"),
-                             sidstr);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               NULL, 0, 0, talloc_tos(), &msg,
+                               ("(&(objectSid=%s)(objectClass=group))"),
+                               sidstr);
        TALLOC_FREE(sidstr);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
 
@@ -743,18 +978,24 @@ static NTSTATUS pdb_ads_delete_dom_group(struct pdb_methods *m,
        }
 
        if (!tldap_entry_dn(msg[0], &dn)) {
+               TALLOC_FREE(msg);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       rc = tldap_delete(state->ld, dn, NULL, NULL);
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               TALLOC_FREE(msg);
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
+       rc = tldap_delete(ld, dn, NULL, 0, NULL, 0);
+       TALLOC_FREE(msg);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_delete failed: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
-               TALLOC_FREE(dn);
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
 
-       TALLOC_FREE(msg);
        return NT_STATUS_OK;
 }
 
@@ -767,19 +1008,83 @@ static NTSTATUS pdb_ads_add_group_mapping_entry(struct pdb_methods *m,
 static NTSTATUS pdb_ads_update_group_mapping_entry(struct pdb_methods *m,
                                                   GROUP_MAP *map)
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+       struct pdb_ads_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
+       struct tldap_mod *mods = NULL;
+       char *filter;
+       struct tldap_message *existing;
+       char *dn;
+       GROUP_MAP *existing_map;
+       int rc, num_mods = 0;
+       bool ret;
+       NTSTATUS status;
+
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
+       filter = talloc_asprintf(talloc_tos(),
+                                "(&(objectsid=%s)(objectclass=group))",
+                                sid_string_talloc(talloc_tos(), &map->sid));
+       if (filter == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       existing_map = talloc_zero(talloc_tos(), GROUP_MAP);
+       if (!existing_map) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = pdb_ads_getgrfilter(m, existing_map, filter,
+                                    talloc_tos(), &existing);
+       TALLOC_FREE(existing_map);
+       TALLOC_FREE(filter);
+
+       if (!tldap_entry_dn(existing, &dn)) {
+               return NT_STATUS_LDAP(TLDAP_DECODING_ERROR);
+       }
+
+       ret = true;
+
+       ret &= tldap_make_mod_fmt(
+               existing, talloc_tos(), &mods, &num_mods, "description",
+               "%s", map->comment);
+       ret &= tldap_make_mod_fmt(
+               existing, talloc_tos(), &mods, &num_mods, "samaccountname",
+               "%s", map->nt_name);
+
+       if (!ret) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (num_mods == 0) {
+               TALLOC_FREE(existing);
+               return NT_STATUS_OK;
+       }
+
+       rc = tldap_modify(ld, dn, mods, num_mods, NULL, 0, NULL, 0);
+       if (rc != TLDAP_SUCCESS) {
+               DEBUG(10, ("ldap_modify for %s failed: %s\n", dn,
+                          tldap_errstr(talloc_tos(), ld, rc)));
+               TALLOC_FREE(existing);
+               return NT_STATUS_LDAP(rc);
+       }
+       TALLOC_FREE(existing);
+       return NT_STATUS_OK;
 }
 
 static NTSTATUS pdb_ads_delete_group_mapping_entry(struct pdb_methods *m,
-                                                  DOM_SID sid)
+                                                  struct dom_sid sid)
 {
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
 static NTSTATUS pdb_ads_enum_group_mapping(struct pdb_methods *m,
-                                          const DOM_SID *sid,
+                                          const struct dom_sid *sid,
                                           enum lsa_SidType sid_name_use,
-                                          GROUP_MAP **pp_rmap,
+                                          GROUP_MAP ***pp_rmap,
                                           size_t *p_num_entries,
                                           bool unix_only)
 {
@@ -788,7 +1093,7 @@ static NTSTATUS pdb_ads_enum_group_mapping(struct pdb_methods *m,
 
 static NTSTATUS pdb_ads_enum_group_members(struct pdb_methods *m,
                                           TALLOC_CTX *mem_ctx,
-                                          const DOM_SID *group,
+                                          const struct dom_sid *group,
                                           uint32 **pmembers,
                                           size_t *pnum_members)
 {
@@ -801,16 +1106,16 @@ static NTSTATUS pdb_ads_enum_group_members(struct pdb_methods *m,
        DATA_BLOB *blobs;
        uint32_t *members;
 
-       sidstr = sid_binstring(talloc_tos(), group);
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), group);
        NT_STATUS_HAVE_NO_MEMORY(sidstr);
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &msg,
-                             "(objectsid=%s)", sidstr);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &msg, "(objectsid=%s)", sidstr);
        TALLOC_FREE(sidstr);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
        switch talloc_array_length(msg) {
@@ -824,8 +1129,10 @@ static NTSTATUS pdb_ads_enum_group_members(struct pdb_methods *m,
                break;
        }
 
-       if (!tldap_entry_values(msg[0], "member", &num_members, &blobs)) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       if (!tldap_entry_values(msg[0], "member", &blobs, &num_members)) {
+               *pmembers = NULL;
+               *pnum_members = 0;
+               return NT_STATUS_OK;
        }
 
        members = talloc_array(mem_ctx, uint32_t, num_members);
@@ -835,7 +1142,7 @@ static NTSTATUS pdb_ads_enum_group_members(struct pdb_methods *m,
 
        for (i=0; i<num_members; i++) {
                struct dom_sid sid;
-               if (!pdb_ads_dnblob2sid(state->ld, &blobs[i], &sid)
+               if (!pdb_ads_dnblob2sid(state, &blobs[i], &sid)
                    || !sid_peek_rid(&sid, &members[i])) {
                        TALLOC_FREE(members);
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
@@ -850,14 +1157,13 @@ static NTSTATUS pdb_ads_enum_group_members(struct pdb_methods *m,
 static NTSTATUS pdb_ads_enum_group_memberships(struct pdb_methods *m,
                                               TALLOC_CTX *mem_ctx,
                                               struct samu *user,
-                                              DOM_SID **pp_sids,
+                                              struct dom_sid **pp_sids,
                                               gid_t **pp_gids,
-                                              size_t *p_num_groups)
+                                              uint32_t *p_num_groups)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
-       struct pdb_ads_samu_private *priv = pdb_ads_get_samu_private(
-               m, user);
+       struct pdb_ads_samu_private *priv;
        const char *attrs[1] = { "objectSid" };
        struct tldap_message **groups;
        int i, rc, count;
@@ -865,29 +1171,44 @@ static NTSTATUS pdb_ads_enum_group_memberships(struct pdb_methods *m,
        struct dom_sid *group_sids;
        gid_t *gids;
 
-       rc = tldap_search_fmt(
-               state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &groups,
-               "(&(member=%s)(grouptype=%d)(objectclass=group))",
-               priv->dn, GTYPE_SECURITY_GLOBAL_GROUP);
-       if (rc != TLDAP_SUCCESS) {
-               DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
-               return NT_STATUS_LDAP(rc);
+       priv = pdb_ads_get_samu_private(m, user);
+       if (priv != NULL) {
+               rc = pdb_ads_search_fmt(
+                       state, state->domaindn, TLDAP_SCOPE_SUB,
+                       attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &groups,
+                       "(&(member=%s)(grouptype=%d)(objectclass=group))",
+                       priv->dn, GTYPE_SECURITY_GLOBAL_GROUP);
+               if (rc != TLDAP_SUCCESS) {
+                       DEBUG(10, ("ldap_search failed %s\n",
+                                  tldap_errstr(talloc_tos(), state->ld, rc)));
+                       return NT_STATUS_LDAP(rc);
+               }
+               count = talloc_array_length(groups);
+       } else {
+               /*
+                * This happens for artificial samu users
+                */
+               DEBUG(10, ("Could not get pdb_ads_samu_private\n"));
+               count = 0;
        }
 
-       count = talloc_array_length(groups);
-
-       group_sids = talloc_array(mem_ctx, struct dom_sid, count);
+       group_sids = talloc_array(mem_ctx, struct dom_sid, count+1);
        if (group_sids == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       gids = talloc_array(mem_ctx, gid_t, count);
+       gids = talloc_array(mem_ctx, gid_t, count+1);
        if (gids == NULL) {
                TALLOC_FREE(group_sids);
                return NT_STATUS_NO_MEMORY;
        }
-       num_groups = 0;
+
+       sid_copy(&group_sids[0], pdb_get_group_sid(user));
+       if (!sid_to_gid(&group_sids[0], &gids[0])) {
+               TALLOC_FREE(gids);
+               TALLOC_FREE(group_sids);
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       num_groups = 1;
 
        for (i=0; i<count; i++) {
                if (!tldap_pull_binsid(groups[i], "objectSid",
@@ -923,12 +1244,19 @@ static NTSTATUS pdb_ads_mod_groupmem(struct pdb_methods *m,
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
        TALLOC_CTX *frame = talloc_stackframe();
+       struct tldap_context *ld;
        struct dom_sid groupsid, membersid;
        char *groupdn, *memberdn;
        struct tldap_mod *mods;
+       int num_mods;
        int rc;
        NTSTATUS status;
 
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
        sid_compose(&groupsid, &state->domainsid, grouprid);
        sid_compose(&membersid, &state->domainsid, memberrid);
 
@@ -944,22 +1272,25 @@ static NTSTATUS pdb_ads_mod_groupmem(struct pdb_methods *m,
        }
 
        mods = NULL;
+       num_mods = 0;
 
-       if (!tldap_add_mod_str(talloc_tos(), &mods, mod_op,
+       if (!tldap_add_mod_str(talloc_tos(), &mods, &num_mods, mod_op,
                               "member", memberdn)) {
                TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
 
-       rc = tldap_modify(state->ld, groupdn, 1, mods, NULL, NULL);
+       rc = tldap_modify(ld, groupdn, mods, num_mods, NULL, 0, NULL, 0);
        TALLOC_FREE(frame);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_modify failed: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
-               if (rc == TLDAP_TYPE_OR_VALUE_EXISTS) {
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
+               if ((mod_op == TLDAP_MOD_ADD) &&
+                   (rc == TLDAP_ALREADY_EXISTS)) {
                        return NT_STATUS_MEMBER_IN_GROUP;
                }
-               if (rc == TLDAP_NO_SUCH_ATTRIBUTE) {
+               if ((mod_op == TLDAP_MOD_DELETE) &&
+                   (rc == TLDAP_UNWILLING_TO_PERFORM)) {
                        return NT_STATUS_MEMBER_NOT_IN_GROUP;
                }
                return NT_STATUS_LDAP(rc);
@@ -990,6 +1321,7 @@ static NTSTATUS pdb_ads_create_alias(struct pdb_methods *m,
        TALLOC_CTX *frame = talloc_stackframe();
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
        const char *attrs[1] = { "objectSid" };
        int num_mods = 0;
        struct tldap_mod *mods = NULL;
@@ -999,6 +1331,11 @@ static NTSTATUS pdb_ads_create_alias(struct pdb_methods *m,
        int rc;
        bool ok = true;
 
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
        dn = talloc_asprintf(talloc_tos(), "cn=%s,cn=users,%s", name,
                             state->domaindn);
        if (dn == NULL) {
@@ -1007,12 +1344,12 @@ static NTSTATUS pdb_ads_create_alias(struct pdb_methods *m,
        }
 
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "samAccountName", "%s",
+               NULL, talloc_tos(), &mods, &num_mods, "samAccountName", "%s",
                name);
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "objectClass", "group");
+               NULL, talloc_tos(), &mods, &num_mods, "objectClass", "group");
        ok &= tldap_make_mod_fmt(
-               NULL, talloc_tos(), &num_mods, &mods, "groupType",
+               NULL, talloc_tos(), &mods, &num_mods, "groupType",
                "%d", (int)GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
 
        if (!ok) {
@@ -1020,21 +1357,21 @@ static NTSTATUS pdb_ads_create_alias(struct pdb_methods *m,
                return NT_STATUS_NO_MEMORY;
        }
 
-       rc = tldap_add(state->ld, dn, num_mods, mods, NULL, NULL);
+       rc = tldap_add(ld, dn, mods, num_mods, NULL, 0, NULL, 0);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_add failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                TALLOC_FREE(frame);
                return NT_STATUS_LDAP(rc);
        }
 
-       rc = tldap_search_fmt(
-               state->ld, state->domaindn, TLDAP_SCOPE_SUB,
+       rc = pdb_ads_search_fmt(
+               state, state->domaindn, TLDAP_SCOPE_SUB,
                attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &alias,
                "(&(objectclass=group)(samaccountname=%s))", name);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("Could not find just created alias %s: %s\n",
-                          name, tldap_errstr(debug_ctx(), state->ld, rc)));
+                          name, tldap_errstr(talloc_tos(), state->ld, rc)));
                TALLOC_FREE(frame);
                return NT_STATUS_LDAP(rc);
        }
@@ -1059,30 +1396,35 @@ static NTSTATUS pdb_ads_create_alias(struct pdb_methods *m,
 }
 
 static NTSTATUS pdb_ads_delete_alias(struct pdb_methods *m,
-                                    const DOM_SID *sid)
+                                    const struct dom_sid *sid)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
        struct tldap_message **alias;
-       char *sidstr, *dn;
+       char *sidstr, *dn = NULL;
        int rc;
 
-       sidstr = sid_binstring(talloc_tos(), sid);
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
        if (sidstr == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             NULL, 0, 0, talloc_tos(), &alias,
-                             "(&(objectSid=%s)(objectclass=group)"
-                             "(|(grouptype=%d)(grouptype=%d)))",
-                             sidstr, GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
-                             GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               NULL, 0, 0, talloc_tos(), &alias,
+                               "(&(objectSid=%s)(objectclass=group)"
+                               "(|(grouptype=%d)(grouptype=%d)))",
+                               sidstr, GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
+                               GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
        TALLOC_FREE(sidstr);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
-               TALLOC_FREE(dn);
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
        if (talloc_array_length(alias) != 1) {
@@ -1096,11 +1438,10 @@ static NTSTATUS pdb_ads_delete_alias(struct pdb_methods *m,
                return NT_STATUS_INTERNAL_ERROR;
        }
 
-       rc = tldap_delete(state->ld, dn, NULL, NULL);
+       rc = tldap_delete(ld, dn, NULL, 0, NULL, 0);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_delete failed: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
-               TALLOC_FREE(dn);
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
 
@@ -1108,11 +1449,12 @@ static NTSTATUS pdb_ads_delete_alias(struct pdb_methods *m,
 }
 
 static NTSTATUS pdb_ads_set_aliasinfo(struct pdb_methods *m,
-                                     const DOM_SID *sid,
+                                     const struct dom_sid *sid,
                                      struct acct_info *info)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
        const char *attrs[3] = { "objectSid", "description",
                                 "samAccountName" };
        struct tldap_message **msg;
@@ -1122,19 +1464,24 @@ static NTSTATUS pdb_ads_set_aliasinfo(struct pdb_methods *m,
        int num_mods;
        bool ok;
 
-       sidstr = sid_binstring(talloc_tos(), sid);
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
        NT_STATUS_HAVE_NO_MEMORY(sidstr);
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
-                             &msg, "(&(objectSid=%s)(objectclass=group)"
-                             "(|(grouptype=%d)(grouptype=%d)))",
-                             sidstr, GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
-                             GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &msg, "(&(objectSid=%s)(objectclass=group)"
+                               "(|(grouptype=%d)(grouptype=%d)))",
+                               sidstr, GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
+                               GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
        TALLOC_FREE(sidstr);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
        switch talloc_array_length(msg) {
@@ -1156,10 +1503,10 @@ static NTSTATUS pdb_ads_set_aliasinfo(struct pdb_methods *m,
        ok = true;
 
        ok &= tldap_make_mod_fmt(
-               msg[0], msg, &num_mods, &mods, "description",
+               msg[0], msg, &mods, &num_mods, "description",
                "%s", info->acct_desc);
        ok &= tldap_make_mod_fmt(
-               msg[0], msg, &num_mods, &mods, "samAccountName",
+               msg[0], msg, &mods, &num_mods, "samAccountName",
                "%s", info->acct_name);
        if (!ok) {
                TALLOC_FREE(msg);
@@ -1171,11 +1518,11 @@ static NTSTATUS pdb_ads_set_aliasinfo(struct pdb_methods *m,
                return NT_STATUS_OK;
        }
 
-       rc = tldap_modify(state->ld, dn, num_mods, mods, NULL, NULL);
+       rc = tldap_modify(ld, dn, mods, num_mods, NULL, 0, NULL, 0);
        TALLOC_FREE(msg);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_modify failed: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
        return NT_STATUS_OK;
@@ -1189,16 +1536,16 @@ static NTSTATUS pdb_ads_sid2dn(struct pdb_ads_state *state,
        char *sidstr, *dn;
        int rc;
 
-       sidstr = sid_binstring(talloc_tos(), sid);
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
        NT_STATUS_HAVE_NO_MEMORY(sidstr);
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             NULL, 0, 0, talloc_tos(), &msg,
-                             "(objectsid=%s)", sidstr);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               NULL, 0, 0, talloc_tos(), &msg,
+                               "(objectsid=%s)", sidstr);
        TALLOC_FREE(sidstr);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
 
@@ -1226,18 +1573,25 @@ static NTSTATUS pdb_ads_sid2dn(struct pdb_ads_state *state,
 }
 
 static NTSTATUS pdb_ads_mod_aliasmem(struct pdb_methods *m,
-                                    const DOM_SID *alias,
-                                    const DOM_SID *member,
+                                    const struct dom_sid *alias,
+                                    const struct dom_sid *member,
                                     int mod_op)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       struct tldap_context *ld;
        TALLOC_CTX *frame = talloc_stackframe();
        struct tldap_mod *mods;
+       int num_mods;
        int rc;
        char *aliasdn, *memberdn;
        NTSTATUS status;
 
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
        status = pdb_ads_sid2dn(state, alias, talloc_tos(), &aliasdn);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10, ("pdb_ads_sid2dn (%s) failed: %s\n",
@@ -1254,18 +1608,19 @@ static NTSTATUS pdb_ads_mod_aliasmem(struct pdb_methods *m,
        }
 
        mods = NULL;
+       num_mods = 0;
 
-       if (!tldap_add_mod_str(talloc_tos(), &mods, mod_op,
+       if (!tldap_add_mod_str(talloc_tos(), &mods, &num_mods, mod_op,
                               "member", memberdn)) {
                TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
 
-       rc = tldap_modify(state->ld, aliasdn, 1, mods, NULL, NULL);
+       rc = tldap_modify(ld, aliasdn, mods, num_mods, NULL, 0, NULL, 0);
        TALLOC_FREE(frame);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_modify failed: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                if (rc == TLDAP_TYPE_OR_VALUE_EXISTS) {
                        return NT_STATUS_MEMBER_IN_ALIAS;
                }
@@ -1279,20 +1634,20 @@ static NTSTATUS pdb_ads_mod_aliasmem(struct pdb_methods *m,
 }
 
 static NTSTATUS pdb_ads_add_aliasmem(struct pdb_methods *m,
-                                    const DOM_SID *alias,
-                                    const DOM_SID *member)
+                                    const struct dom_sid *alias,
+                                    const struct dom_sid *member)
 {
        return pdb_ads_mod_aliasmem(m, alias, member, TLDAP_MOD_ADD);
 }
 
 static NTSTATUS pdb_ads_del_aliasmem(struct pdb_methods *m,
-                                    const DOM_SID *alias,
-                                    const DOM_SID *member)
+                                    const struct dom_sid *alias,
+                                    const struct dom_sid *member)
 {
        return pdb_ads_mod_aliasmem(m, alias, member, TLDAP_MOD_DELETE);
 }
 
-static bool pdb_ads_dnblob2sid(struct tldap_context *ld, DATA_BLOB *dnblob,
+static bool pdb_ads_dnblob2sid(struct pdb_ads_state *state, DATA_BLOB *dnblob,
                               struct dom_sid *psid)
 {
        const char *attrs[1] = { "objectSid" };
@@ -1303,13 +1658,12 @@ static bool pdb_ads_dnblob2sid(struct tldap_context *ld, DATA_BLOB *dnblob,
        bool ret;
 
        if (!convert_string_talloc(talloc_tos(), CH_UTF8, CH_UNIX,
-                                  dnblob->data, dnblob->length, &dn, &len,
-                                  false)) {
+                                  dnblob->data, dnblob->length, &dn, &len)) {
                return false;
        }
-       rc = tldap_search_fmt(ld, dn, TLDAP_SCOPE_BASE,
-                             attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
-                             &msg, "(objectclass=*)");
+       rc = pdb_ads_search_fmt(state, dn, TLDAP_SCOPE_BASE,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &msg, "(objectclass=*)");
        TALLOC_FREE(dn);
        if (talloc_array_length(msg) != 1) {
                DEBUG(10, ("Got %d objects, expected one\n",
@@ -1324,9 +1678,9 @@ static bool pdb_ads_dnblob2sid(struct tldap_context *ld, DATA_BLOB *dnblob,
 }
 
 static NTSTATUS pdb_ads_enum_aliasmem(struct pdb_methods *m,
-                                     const DOM_SID *alias,
+                                     const struct dom_sid *alias,
                                      TALLOC_CTX *mem_ctx,
-                                     DOM_SID **pmembers,
+                                     struct dom_sid **pmembers,
                                      size_t *pnum_members)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
@@ -1338,16 +1692,16 @@ static NTSTATUS pdb_ads_enum_aliasmem(struct pdb_methods *m,
        DATA_BLOB *blobs;
        struct dom_sid *members;
 
-       sidstr = sid_binstring(talloc_tos(), alias);
+       sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), alias);
        NT_STATUS_HAVE_NO_MEMORY(sidstr);
 
-       rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-                             attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &msg,
-                             "(objectsid=%s)", sidstr);
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &msg, "(objectsid=%s)", sidstr);
        TALLOC_FREE(sidstr);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search failed %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return NT_STATUS_LDAP(rc);
        }
        switch talloc_array_length(msg) {
@@ -1361,8 +1715,10 @@ static NTSTATUS pdb_ads_enum_aliasmem(struct pdb_methods *m,
                break;
        }
 
-       if (!tldap_entry_values(msg[0], "member", &num_members, &blobs)) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       if (!tldap_entry_values(msg[0], "member", &blobs, &num_members)) {
+               *pmembers = NULL;
+               *pnum_members = 0;
+               return NT_STATUS_OK;
        }
 
        members = talloc_array(mem_ctx, struct dom_sid, num_members);
@@ -1371,7 +1727,7 @@ static NTSTATUS pdb_ads_enum_aliasmem(struct pdb_methods *m,
        }
 
        for (i=0; i<num_members; i++) {
-               if (!pdb_ads_dnblob2sid(state->ld, &blobs[i], &members[i])) {
+               if (!pdb_ads_dnblob2sid(state, &blobs[i], &members[i])) {
                        TALLOC_FREE(members);
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
@@ -1384,17 +1740,102 @@ static NTSTATUS pdb_ads_enum_aliasmem(struct pdb_methods *m,
 
 static NTSTATUS pdb_ads_enum_alias_memberships(struct pdb_methods *m,
                                               TALLOC_CTX *mem_ctx,
-                                              const DOM_SID *domain_sid,
-                                              const DOM_SID *members,
+                                              const struct dom_sid *domain_sid,
+                                              const struct dom_sid *members,
                                               size_t num_members,
-                                              uint32 **pp_alias_rids,
-                                              size_t *p_num_alias_rids)
+                                              uint32_t **palias_rids,
+                                              size_t *pnum_alias_rids)
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+       struct pdb_ads_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_ads_state);
+       const char *attrs[1] = { "objectSid" };
+       struct tldap_message **msg = NULL;
+       uint32_t *alias_rids = NULL;
+       size_t num_alias_rids = 0;
+       int i, rc, count;
+       bool got_members = false;
+       char *filter;
+       NTSTATUS status;
+
+       /*
+        * TODO: Get the filter right so that we only get the aliases from
+        * either the SAM or BUILTIN
+        */
+
+       filter = talloc_asprintf(talloc_tos(),
+                                "(&(|(grouptype=%d)(grouptype=%d))"
+                                "(objectclass=group)(|",
+                                GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
+                                GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+       if (filter == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i=0; i<num_members; i++) {
+               char *dn;
+
+               status = pdb_ads_sid2dn(state, &members[i], talloc_tos(), &dn);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("pdb_ads_sid2dn failed for %s: %s\n",
+                                  sid_string_dbg(&members[i]),
+                                  nt_errstr(status)));
+                       continue;
+               }
+               filter = talloc_asprintf_append_buffer(
+                       filter, "(member=%s)", dn);
+               TALLOC_FREE(dn);
+               if (filter == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               got_members = true;
+       }
+
+       if (!got_members) {
+               goto done;
+       }
+
+       rc = pdb_ads_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &msg, "%s))", filter);
+       TALLOC_FREE(filter);
+       if (rc != TLDAP_SUCCESS) {
+               DEBUG(10, ("tldap_search failed %s\n",
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
+               return NT_STATUS_LDAP(rc);
+       }
+
+       count = talloc_array_length(msg);
+       if (count == 0) {
+               goto done;
+       }
+
+       alias_rids = talloc_array(mem_ctx, uint32_t, count);
+       if (alias_rids == NULL) {
+               TALLOC_FREE(msg);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i=0; i<count; i++) {
+               struct dom_sid sid;
+
+               if (!tldap_pull_binsid(msg[i], "objectSid", &sid)) {
+                       DEBUG(10, ("Could not pull SID for member %d\n", i));
+                       continue;
+               }
+               if (sid_peek_check_rid(domain_sid, &sid,
+                                      &alias_rids[num_alias_rids])) {
+                       num_alias_rids += 1;
+               }
+       }
+done:
+       TALLOC_FREE(msg);
+       *palias_rids = alias_rids;
+       *pnum_alias_rids = 0;
+       return NT_STATUS_OK;
 }
 
 static NTSTATUS pdb_ads_lookup_rids(struct pdb_methods *m,
-                                   const DOM_SID *domain_sid,
+                                   const struct dom_sid *domain_sid,
                                    int num_rids,
                                    uint32 *rids,
                                    const char **names,
@@ -1422,17 +1863,17 @@ static NTSTATUS pdb_ads_lookup_rids(struct pdb_methods *m,
 
                sid_compose(&sid, domain_sid, rids[i]);
 
-               sidstr = sid_binstring(talloc_tos(), &sid);
+               sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), &sid);
                NT_STATUS_HAVE_NO_MEMORY(sidstr);
 
-               rc = tldap_search_fmt(state->ld, state->domaindn,
-                                     TLDAP_SCOPE_SUB, attrs,
-                                     ARRAY_SIZE(attrs), 0, talloc_tos(),
-                                     &msg, "(objectsid=%s)", sidstr);
+               rc = pdb_ads_search_fmt(state, state->domaindn,
+                                       TLDAP_SCOPE_SUB, attrs,
+                                       ARRAY_SIZE(attrs), 0, talloc_tos(),
+                                       &msg, "(objectsid=%s)", sidstr);
                TALLOC_FREE(sidstr);
                if (rc != TLDAP_SUCCESS) {
                        DEBUG(10, ("ldap_search failed %s\n",
-                                  tldap_errstr(debug_ctx(), state->ld, rc)));
+                                  tldap_errstr(talloc_tos(), state->ld, rc)));
                        continue;
                }
 
@@ -1456,7 +1897,7 @@ static NTSTATUS pdb_ads_lookup_rids(struct pdb_methods *m,
                        DEBUG(10, ("no samAccountType"));
                        continue;
                }
-               lsa_attrs[i] = ads_atype_map(attr);
+               lsa_attrs[i] = ds_atype_map(attr);
                num_mapped += 1;
        }
 
@@ -1470,7 +1911,7 @@ static NTSTATUS pdb_ads_lookup_rids(struct pdb_methods *m,
 }
 
 static NTSTATUS pdb_ads_lookup_names(struct pdb_methods *m,
-                                    const DOM_SID *domain_sid,
+                                    const struct dom_sid *domain_sid,
                                     int num_names,
                                     const char **pp_names,
                                     uint32 *rids,
@@ -1480,16 +1921,18 @@ static NTSTATUS pdb_ads_lookup_names(struct pdb_methods *m,
 }
 
 static NTSTATUS pdb_ads_get_account_policy(struct pdb_methods *m,
-                                          int policy_index, uint32 *value)
+                                          enum pdb_policy_type type,
+                                          uint32_t *value)
 {
-       return account_policy_get(policy_index, value)
+       return account_policy_get(type, value)
                ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
 }
 
 static NTSTATUS pdb_ads_set_account_policy(struct pdb_methods *m,
-                                          int policy_index, uint32 value)
+                                          enum pdb_policy_type type,
+                                          uint32_t value)
 {
-       return account_policy_set(policy_index, value)
+       return account_policy_set(type, value)
                ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
 }
 
@@ -1548,6 +1991,7 @@ static void pdb_ads_search_end(struct pdb_search *search)
 static bool pdb_ads_search_filter(struct pdb_methods *m,
                                  struct pdb_search *search,
                                  const char *filter,
+                                 uint32_t acct_flags,
                                  struct pdb_ads_search_state **pstate)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
@@ -1562,14 +2006,15 @@ static bool pdb_ads_search_filter(struct pdb_methods *m,
        if (sstate == NULL) {
                return false;
        }
+       sstate->acct_flags = acct_flags;
 
-       rc = tldap_search_fmt(
-               state->ld, state->domaindn, TLDAP_SCOPE_SUB,
+       rc = pdb_ads_search_fmt(
+               state, state->domaindn, TLDAP_SCOPE_SUB,
                attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &users,
                "%s", filter);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("ldap_search_ext_s failed: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                return false;
        }
 
@@ -1587,6 +2032,7 @@ static bool pdb_ads_search_filter(struct pdb_methods *m,
        for (i=0; i<num_users; i++) {
                struct samr_displayentry *e;
                struct dom_sid sid;
+               uint32_t ctrl;
 
                e = &sstate->entries[sstate->num_entries];
 
@@ -1596,19 +2042,51 @@ static bool pdb_ads_search_filter(struct pdb_methods *m,
                        continue;
                }
                sid_peek_rid(&sid, &e->rid);
-               e->acct_flags = ACB_NORMAL;
-               e->account_name = tldap_talloc_single_attribute(
-                       users[i], "samAccountName", sstate->entries);
+
+               if (tldap_pull_uint32(users[i], "userAccountControl", &ctrl)) {
+
+                       e->acct_flags = ds_uf2acb(ctrl);
+
+                       DEBUG(10, ("pdb_ads_search_filter: Found %x, "
+                                  "filter %x\n", (int)e->acct_flags,
+                                  (int)sstate->acct_flags));
+
+
+                       if ((sstate->acct_flags != 0) &&
+                           ((sstate->acct_flags & e->acct_flags) == 0)) {
+                               continue;
+                       }
+
+                       if (e->acct_flags & (ACB_WSTRUST|ACB_SVRTRUST)) {
+                               e->acct_flags |= ACB_NORMAL;
+                       }
+               } else {
+                       e->acct_flags = ACB_NORMAL;
+               }
+
+               if (e->rid == DOMAIN_RID_GUEST) {
+                       /*
+                        * Guest is specially crafted in s3. Make
+                        * QueryDisplayInfo match QueryUserInfo
+                        */
+                       e->account_name = lp_guestaccount();
+                       e->fullname = lp_guestaccount();
+                       e->description = "";
+                       e->acct_flags = ACB_NORMAL;
+               } else {
+                       e->account_name = tldap_talloc_single_attribute(
+                               users[i], "samAccountName", sstate->entries);
+                       e->fullname = tldap_talloc_single_attribute(
+                               users[i], "displayName", sstate->entries);
+                       e->description = tldap_talloc_single_attribute(
+                               users[i], "description", sstate->entries);
+               }
                if (e->account_name == NULL) {
                        return false;
                }
-               e->fullname = tldap_talloc_single_attribute(
-                        users[i], "displayName", sstate->entries);
                if (e->fullname == NULL) {
                        e->fullname = "";
                }
-               e->description = tldap_talloc_single_attribute(
-                        users[i], "description", sstate->entries);
                if (e->description == NULL) {
                        e->description = "";
                }
@@ -1631,13 +2109,33 @@ static bool pdb_ads_search_users(struct pdb_methods *m,
                                 uint32 acct_flags)
 {
        struct pdb_ads_search_state *sstate;
+       char *filter;
        bool ret;
 
-       ret = pdb_ads_search_filter(m, search, "(objectclass=user)", &sstate);
+       DEBUG(10, ("pdb_ads_search_users got flags %x\n", acct_flags));
+
+       if (acct_flags & ACB_NORMAL) {
+               filter = talloc_asprintf(
+                       talloc_tos(),
+                       "(&(objectclass=user)(sAMAccountType=%d))",
+                       ATYPE_NORMAL_ACCOUNT);
+       } else if (acct_flags & ACB_WSTRUST) {
+               filter = talloc_asprintf(
+                       talloc_tos(),
+                       "(&(objectclass=user)(sAMAccountType=%d))",
+                       ATYPE_WORKSTATION_TRUST);
+       } else {
+               filter = talloc_strdup(talloc_tos(), "(objectclass=user)");
+       }
+       if (filter == NULL) {
+               return false;
+       }
+
+       ret = pdb_ads_search_filter(m, search, filter, acct_flags, &sstate);
+       TALLOC_FREE(filter);
        if (!ret) {
                return false;
        }
-       sstate->acct_flags = acct_flags;
        return true;
 }
 
@@ -1654,18 +2152,17 @@ static bool pdb_ads_search_groups(struct pdb_methods *m,
        if (filter == NULL) {
                return false;
        }
-       ret = pdb_ads_search_filter(m, search, filter, &sstate);
+       ret = pdb_ads_search_filter(m, search, filter, 0, &sstate);
        TALLOC_FREE(filter);
        if (!ret) {
                return false;
        }
-       sstate->acct_flags = 0;
        return true;
 }
 
 static bool pdb_ads_search_aliases(struct pdb_methods *m,
                                   struct pdb_search *search,
-                                  const DOM_SID *sid)
+                                  const struct dom_sid *sid)
 {
        struct pdb_ads_search_state *sstate;
        char *filter;
@@ -1680,23 +2177,16 @@ static bool pdb_ads_search_aliases(struct pdb_methods *m,
        if (filter == NULL) {
                return false;
        }
-       ret = pdb_ads_search_filter(m, search, filter, &sstate);
+       ret = pdb_ads_search_filter(m, search, filter, 0, &sstate);
        TALLOC_FREE(filter);
        if (!ret) {
                return false;
        }
-       sstate->acct_flags = 0;
        return true;
 }
 
-static bool pdb_ads_uid_to_rid(struct pdb_methods *m, uid_t uid,
-                              uint32 *rid)
-{
-       return false;
-}
-
 static bool pdb_ads_uid_to_sid(struct pdb_methods *m, uid_t uid,
-                              DOM_SID *sid)
+                              struct dom_sid *sid)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
@@ -1705,7 +2195,7 @@ static bool pdb_ads_uid_to_sid(struct pdb_methods *m, uid_t uid,
 }
 
 static bool pdb_ads_gid_to_sid(struct pdb_methods *m, gid_t gid,
-                              DOM_SID *sid)
+                              struct dom_sid *sid)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
@@ -1713,56 +2203,71 @@ static bool pdb_ads_gid_to_sid(struct pdb_methods *m, gid_t gid,
        return true;
 }
 
-static bool pdb_ads_sid_to_id(struct pdb_methods *m, const DOM_SID *sid,
-                             union unid_t *id, enum lsa_SidType *type)
+static bool pdb_ads_sid_to_id(struct pdb_methods *m, const struct dom_sid *sid,
+                             uid_t *uid, gid_t *gid, enum lsa_SidType *type)
 {
        struct pdb_ads_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_ads_state);
+       const char *attrs[4] = { "objectClass", "samAccountType",
+                                "uidNumber", "gidNumber" };
        struct tldap_message **msg;
-       char *sidstr;
-       uint32_t rid;
+       char *sidstr, *base;
+       uint32_t atype;
        int rc;
+       bool ret = false;
 
-       /*
-        * This is a big, big hack: Just hard-code the rid as uid/gid.
-        */
-
-       sid_peek_rid(sid, &rid);
+       *uid = -1;
+       *gid = -1;
 
-       sidstr = sid_binstring(talloc_tos(), sid);
+       sidstr = sid_binstring_hex(sid);
        if (sidstr == NULL) {
                return false;
        }
+       base = talloc_asprintf(talloc_tos(), "<SID=%s>", sidstr);
+       SAFE_FREE(sidstr);
 
-       rc = tldap_search_fmt(
-               state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-               NULL, 0, 0, talloc_tos(), &msg,
-               "(&(objectsid=%s)(objectclass=user))", sidstr);
-       if ((rc == TLDAP_SUCCESS) && (talloc_array_length(msg) > 0)) {
-               id->uid = rid;
-               *type = SID_NAME_USER;
-               TALLOC_FREE(sidstr);
-               return true;
-       }
+       rc = pdb_ads_search_fmt(
+               state, base, TLDAP_SCOPE_BASE,
+               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &msg,
+               "(objectclass=*)");
+       TALLOC_FREE(base);
 
-       rc = tldap_search_fmt(
-               state->ld, state->domaindn, TLDAP_SCOPE_SUB,
-               NULL, 0, 0, talloc_tos(), &msg,
-               "(&(objectsid=%s)(objectclass=group))", sidstr);
-       if ((rc == TLDAP_SUCCESS) && (talloc_array_length(msg) > 0)) {
-               id->gid = rid;
+       if (rc != TLDAP_SUCCESS) {
+               DEBUG(10, ("pdb_ads_search_fmt failed: %s\n",
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
+               return false;
+       }
+       if (talloc_array_length(msg) != 1) {
+               DEBUG(10, ("Got %d objects, expected 1\n",
+                          (int)talloc_array_length(msg)));
+               goto fail;
+       }
+       if (!tldap_pull_uint32(msg[0], "samAccountType", &atype)) {
+               DEBUG(10, ("samAccountType not found\n"));
+               goto fail;
+       }
+       if (atype == ATYPE_ACCOUNT) {
+               *type = SID_NAME_USER;
+               if (!tldap_pull_uint32(msg[0], "uidNumber", uid)) {
+                       DEBUG(10, ("Did not find uidNumber\n"));
+                       goto fail;
+               }
+       } else {
                *type = SID_NAME_DOM_GRP;
-               TALLOC_FREE(sidstr);
-               return true;
+               if (!tldap_pull_uint32(msg[0], "gidNumber", gid)) {
+                       DEBUG(10, ("Did not find gidNumber\n"));
+                       goto fail;
+               }
        }
-
-       TALLOC_FREE(sidstr);
-       return false;
+       ret = true;
+fail:
+       TALLOC_FREE(msg);
+       return ret;
 }
 
-static bool pdb_ads_rid_algorithm(struct pdb_methods *m)
+static uint32_t pdb_ads_capabilities(struct pdb_methods *m)
 {
-       return false;
+       return PDB_CAP_STORE_RIDS | PDB_CAP_ADS;
 }
 
 static bool pdb_ads_new_rid(struct pdb_methods *m, uint32 *rid)
@@ -1772,7 +2277,7 @@ static bool pdb_ads_new_rid(struct pdb_methods *m, uint32 *rid)
 
 static bool pdb_ads_get_trusteddom_pw(struct pdb_methods *m,
                                      const char *domain, char** pwd,
-                                     DOM_SID *sid,
+                                     struct dom_sid *sid,
                                      time_t *pass_last_set_time)
 {
        return false;
@@ -1780,7 +2285,7 @@ static bool pdb_ads_get_trusteddom_pw(struct pdb_methods *m,
 
 static bool pdb_ads_set_trusteddom_pw(struct pdb_methods *m,
                                      const char* domain, const char* pwd,
-                                     const DOM_SID *sid)
+                                     const struct dom_sid *sid)
 {
        return false;
 }
@@ -1796,12 +2301,15 @@ static NTSTATUS pdb_ads_enum_trusteddoms(struct pdb_methods *m,
                                         uint32 *num_domains,
                                         struct trustdom_info ***domains)
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+       *num_domains = 0;
+       *domains = NULL;
+       return NT_STATUS_OK;
 }
 
 static void pdb_ads_init_methods(struct pdb_methods *m)
 {
        m->name = "ads";
+       m->get_domain_info = pdb_ads_get_domain_info;
        m->getsampwnam = pdb_ads_getsampwnam;
        m->getsampwsid = pdb_ads_getsampwsid;
        m->create_user = pdb_ads_create_user;
@@ -1841,11 +2349,10 @@ static void pdb_ads_init_methods(struct pdb_methods *m)
        m->search_users = pdb_ads_search_users;
        m->search_groups = pdb_ads_search_groups;
        m->search_aliases = pdb_ads_search_aliases;
-       m->uid_to_rid = pdb_ads_uid_to_rid;
        m->uid_to_sid = pdb_ads_uid_to_sid;
        m->gid_to_sid = pdb_ads_gid_to_sid;
        m->sid_to_id = pdb_ads_sid_to_id;
-       m->rid_algorithm = pdb_ads_rid_algorithm;
+       m->capabilities = pdb_ads_capabilities;
        m->new_rid = pdb_ads_new_rid;
        m->get_trusteddom_pw = pdb_ads_get_trusteddom_pw;
        m->set_trusteddom_pw = pdb_ads_set_trusteddom_pw;
@@ -1862,56 +2369,141 @@ static void free_private_data(void **vp)
        return;
 }
 
-static NTSTATUS pdb_ads_connect(struct pdb_ads_state *state,
-                               const char *location)
+/*
+  this is used to catch debug messages from events
+*/
+static void s3_tldap_debug(void *context, enum tldap_debug_level level,
+                          const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
+
+static void s3_tldap_debug(void *context, enum tldap_debug_level level,
+                          const char *fmt, va_list ap)
+{
+       int samba_level = -1;
+       char *s = NULL;
+       switch (level) {
+       case TLDAP_DEBUG_FATAL:
+               samba_level = 0;
+               break;
+       case TLDAP_DEBUG_ERROR:
+               samba_level = 1;
+               break;
+       case TLDAP_DEBUG_WARNING:
+               samba_level = 2;
+               break;
+       case TLDAP_DEBUG_TRACE:
+               samba_level = 11;
+               break;
+
+       };
+       if (vasprintf(&s, fmt, ap) == -1) {
+               return;
+       }
+       DEBUG(samba_level, ("tldap: %s", s));
+       free(s);
+}
+
+static struct tldap_context *pdb_ads_ld(struct pdb_ads_state *state)
 {
-       const char *rootdse_attrs[2] = {
-               "defaultNamingContext", "configurationNamingContext" };
-       const char *domain_attrs[1] = { "objectSid" };
-       const char *ncname_attrs[1] = { "netbiosname" };
-       struct tldap_message **rootdse, **domain, **ncname;
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct sockaddr_un sunaddr;
        NTSTATUS status;
-       int num_domains;
-       int fd, rc;
+       int fd;
 
-       ZERO_STRUCT(sunaddr);
-       sunaddr.sun_family = AF_UNIX;
-       strncpy(sunaddr.sun_path, location, sizeof(sunaddr.sun_path) - 1);
+       if (tldap_connection_ok(state->ld)) {
+               return state->ld;
+       }
+       TALLOC_FREE(state->ld);
 
-       status = open_socket_out((struct sockaddr_storage *)(void *)&sunaddr,
-                                0, 0, &fd);
+       status = open_socket_out(
+               (struct sockaddr_storage *)(void *)&state->socket_address,
+               0, 0, &fd);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(10, ("Could not connect to %s: %s\n", location,
-                          nt_errstr(status)));
-               goto done;
+               DEBUG(10, ("Could not connect to %s: %s\n",
+                          state->socket_address.sun_path, nt_errstr(status)));
+               return NULL;
        }
 
+       set_blocking(fd, false);
+
        state->ld = tldap_context_create(state, fd);
        if (state->ld == NULL) {
                close(fd);
-               status = NT_STATUS_NO_MEMORY;
+               return NULL;
+       }
+       tldap_set_debug(state->ld, s3_tldap_debug, NULL);
+
+       return state->ld;
+}
+
+int pdb_ads_search_fmt(struct pdb_ads_state *state, const char *base,
+                      int scope, const char *attrs[], int num_attrs,
+                      int attrsonly,
+                      TALLOC_CTX *mem_ctx, struct tldap_message ***res,
+                      const char *fmt, ...)
+{
+       struct tldap_context *ld;
+       va_list ap;
+       int ret;
+
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return TLDAP_SERVER_DOWN;
+       }
+
+       va_start(ap, fmt);
+       ret = tldap_search_va(ld, base, scope, attrs, num_attrs, attrsonly,
+                             mem_ctx, res, fmt, ap);
+       va_end(ap);
+
+       if (ret != TLDAP_SERVER_DOWN) {
+               return ret;
+       }
+
+       /* retry once */
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               return TLDAP_SERVER_DOWN;
+       }
+
+       va_start(ap, fmt);
+       ret = tldap_search_va(ld, base, scope, attrs, num_attrs, attrsonly,
+                             mem_ctx, res, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
+static NTSTATUS pdb_ads_connect(struct pdb_ads_state *state,
+                               const char *location)
+{
+       const char *domain_attrs[2] = { "objectSid", "objectGUID" };
+       const char *ncname_attrs[1] = { "netbiosname" };
+       struct tldap_context *ld;
+       struct tldap_message *rootdse, **domain, **ncname;
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status;
+       int num_domains;
+       int rc;
+
+       ZERO_STRUCT(state->socket_address);
+       state->socket_address.sun_family = AF_UNIX;
+       strlcpy(state->socket_address.sun_path, location,
+               sizeof(state->socket_address.sun_path));
+
+       ld = pdb_ads_ld(state);
+       if (ld == NULL) {
+               status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
                goto done;
        }
 
-       rc = tldap_search_fmt(
-               state->ld, "", TLDAP_SCOPE_BASE,
-               rootdse_attrs, ARRAY_SIZE(rootdse_attrs), 0,
-               talloc_tos(), &rootdse, "(objectclass=*)");
+       rc = tldap_fetch_rootdse(ld);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("Could not retrieve rootdse: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                status = NT_STATUS_LDAP(rc);
                goto done;
        }
-       if (talloc_array_length(rootdse) != 1) {
-               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
-               goto done;
-       }
+       rootdse = tldap_rootdse(state->ld);
 
        state->domaindn = tldap_talloc_single_attribute(
-               rootdse[0], "defaultNamingContext", state);
+               rootdse, "defaultNamingContext", state);
        if (state->domaindn == NULL) {
                DEBUG(10, ("Could not get defaultNamingContext\n"));
                status = NT_STATUS_INTERNAL_DB_CORRUPTION;
@@ -1920,8 +2512,8 @@ static NTSTATUS pdb_ads_connect(struct pdb_ads_state *state,
        DEBUG(10, ("defaultNamingContext = %s\n", state->domaindn));
 
        state->configdn = tldap_talloc_single_attribute(
-               rootdse[0], "configurationNamingContext", state);
-       if (state->domaindn == NULL) {
+               rootdse, "configurationNamingContext", state);
+       if (state->configdn == NULL) {
                DEBUG(10, ("Could not get configurationNamingContext\n"));
                status = NT_STATUS_INTERNAL_DB_CORRUPTION;
                goto done;
@@ -1931,13 +2523,13 @@ static NTSTATUS pdb_ads_connect(struct pdb_ads_state *state,
        /*
         * Figure out our domain's SID
         */
-       rc = tldap_search_fmt(
-               state->ld, state->domaindn, TLDAP_SCOPE_BASE,
+       rc = pdb_ads_search_fmt(
+               state, state->domaindn, TLDAP_SCOPE_BASE,
                domain_attrs, ARRAY_SIZE(domain_attrs), 0,
                talloc_tos(), &domain, "(objectclass=*)");
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("Could not retrieve domain: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                status = NT_STATUS_LDAP(rc);
                goto done;
        }
@@ -1953,18 +2545,23 @@ static NTSTATUS pdb_ads_connect(struct pdb_ads_state *state,
                status = NT_STATUS_INTERNAL_DB_CORRUPTION;
                goto done;
        }
+       if (!tldap_pull_guid(domain[0], "objectGUID", &state->domainguid)) {
+               DEBUG(10, ("Could not retrieve domain GUID\n"));
+               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               goto done;
+       }
        DEBUG(10, ("Domain SID: %s\n", sid_string_dbg(&state->domainsid)));
 
        /*
         * Figure out our domain's short name
         */
-       rc = tldap_search_fmt(
-               state->ld, state->configdn, TLDAP_SCOPE_SUB,
+       rc = pdb_ads_search_fmt(
+               state, state->configdn, TLDAP_SCOPE_SUB,
                ncname_attrs, ARRAY_SIZE(ncname_attrs), 0,
                talloc_tos(), &ncname, "(ncname=%s)", state->domaindn);
        if (rc != TLDAP_SUCCESS) {
                DEBUG(10, ("Could not retrieve ncname: %s\n",
-                          tldap_errstr(debug_ctx(), state->ld, rc)));
+                          tldap_errstr(talloc_tos(), state->ld, rc)));
                status = NT_STATUS_LDAP(rc);
                goto done;
        }
@@ -1997,6 +2594,42 @@ done:
        return status;
 }
 
+static NTSTATUS pdb_ads_init_secrets(struct pdb_methods *m)
+{
+#if _SAMBA_BUILD_ == 4
+       struct pdb_domain_info *dom_info;
+       bool ret;
+
+       dom_info = pdb_ads_get_domain_info(m, m);
+       if (!dom_info) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       secrets_clear_domain_protection(dom_info->name);
+       ret = secrets_store_domain_sid(dom_info->name,
+                                      &dom_info->sid);
+       if (!ret) {
+               goto done;
+       }
+       ret = secrets_store_domain_guid(dom_info->name,
+                                       &dom_info->guid);
+       if (!ret) {
+               goto done;
+       }
+       ret = secrets_mark_domain_protected(dom_info->name);
+       if (!ret) {
+               goto done;
+       }
+
+done:
+       TALLOC_FREE(dom_info);
+       if (!ret) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+#endif
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS pdb_init_ads(struct pdb_methods **pdb_method,
                             const char *location)
 {
@@ -2005,11 +2638,11 @@ static NTSTATUS pdb_init_ads(struct pdb_methods **pdb_method,
        char *tmp = NULL;
        NTSTATUS status;
 
-       m = talloc(talloc_autofree_context(), struct pdb_methods);
+       m = talloc(NULL, struct pdb_methods);
        if (m == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       state = talloc(m, struct pdb_ads_state);
+       state = talloc_zero(m, struct pdb_ads_state);
        if (state == NULL) {
                goto nomem;
        }
@@ -2032,6 +2665,12 @@ static NTSTATUS pdb_init_ads(struct pdb_methods **pdb_method,
                goto fail;
        }
 
+       status = pdb_ads_init_secrets(m);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("pdb_ads_init_secrets failed!\n"));
+               goto fail;
+       }
+
        *pdb_method = m;
        return NT_STATUS_OK;
 nomem: