docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source3 / passdb / pdb_samba_dsdb.c
index 3fc266c4e264c9f58888b8338e56c9d6d79bba77..8ed5799ac895c1301b813eb9d0b472221311d521 100644 (file)
@@ -28,6 +28,8 @@
 #include "libcli/security/dom_sid.h"
 #include "source4/winbind/idmap.h"
 #include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
 #include "libds/common/flag_mapping.h"
 #include "source4/lib/events/events.h"
 #include "source4/auth/session.h"
 #include "lib/param/param.h"
 #include "source4/dsdb/common/util.h"
 #include "source3/include/secrets.h"
+#include "source4/auth/auth_sam.h"
+#include "auth/credentials/credentials.h"
+#include "lib/util/base64.h"
+#include "libcli/ldap/ldap_ndr.h"
+#include "lib/util/util_ldb.h"
 
 struct pdb_samba_dsdb_state {
        struct tevent_context *ev;
@@ -148,7 +155,8 @@ static struct ldb_message *pdb_samba_dsdb_get_samu_private(
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_samba_dsdb_state);
        struct ldb_message *msg;
-       char *sidstr, *filter;
+       struct dom_sid_buf sidstr;
+       char *filter;
        NTSTATUS status;
 
        msg = (struct ldb_message *)
@@ -158,14 +166,10 @@ static struct ldb_message *pdb_samba_dsdb_get_samu_private(
                return talloc_get_type_abort(msg, struct ldb_message);
        }
 
-       sidstr = dom_sid_string(talloc_tos(), pdb_get_user_sid(sam));
-       if (sidstr == NULL) {
-               return NULL;
-       }
-
        filter = talloc_asprintf(
-               talloc_tos(), "(&(objectsid=%s)(objectclass=user))", sidstr);
-       TALLOC_FREE(sidstr);
+               talloc_tos(),
+               "(&(objectsid=%s)(objectclass=user))",
+               dom_sid_str_buf(pdb_get_user_sid(sam), &sidstr));
        if (filter == NULL) {
                return NULL;
        }
@@ -259,9 +263,13 @@ static NTSTATUS pdb_samba_dsdb_init_sam_from_priv(struct pdb_methods *m,
                pdb_set_workstations(sam, str, PDB_SET);
        }
 
-       str = ldb_msg_find_attr_as_string(msg, "userParameters",
-                                           NULL);
-       if (str != NULL) {
+       blob = ldb_msg_find_ldb_val(msg, "userParameters");
+       if (blob != NULL) {
+               str = base64_encode_data_blob(frame, *blob);
+               if (str == NULL) {
+                       DEBUG(0, ("base64_encode_data_blob() failed\n"));
+                       goto fail;
+               }
                pdb_set_munged_dial(sam, str, PDB_SET);
        }
 
@@ -272,12 +280,12 @@ static NTSTATUS pdb_samba_dsdb_init_sam_from_priv(struct pdb_methods *m,
        }
        pdb_set_user_sid(sam, sid, PDB_SET);
 
-       n = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
+       n = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
        if (n == 0) {
                DEBUG(10, ("Could not pull userAccountControl\n"));
                goto fail;
        }
-       pdb_set_acct_ctrl(sam, ds_uf2acb(n), PDB_SET);
+       pdb_set_acct_ctrl(sam, n, PDB_SET);
 
        blob = ldb_msg_find_ldb_val(msg, "unicodePwd");
        if (blob) {
@@ -339,6 +347,7 @@ static int pdb_samba_dsdb_replace_by_sam(struct pdb_samba_dsdb_state *state,
 
        msg = ldb_msg_new(frame);
        if (!msg) {
+               talloc_free(frame);
                return false;
        }
 
@@ -356,7 +365,7 @@ static int pdb_samba_dsdb_replace_by_sam(struct pdb_samba_dsdb_state *state,
        /* If we set a plaintext password, the system will
         * force the pwdLastSet to now() */
        if (need_update(sam, PDB_PASSLASTSET)) {
-               dsdb_flags = DSDB_PASSWORD_BYPASS_LAST_SET;
+               dsdb_flags |= DSDB_PASSWORD_BYPASS_LAST_SET;
 
                ret |= pdb_samba_dsdb_add_time(msg, "pwdLastSet",
                                           pdb_get_pass_last_set_time(sam));
@@ -375,6 +384,7 @@ static int pdb_samba_dsdb_replace_by_sam(struct pdb_samba_dsdb_state *state,
                                           pw, strlen(pw),
                                           (void *)&pw_utf16.data,
                                           &pw_utf16.length)) {
+                       talloc_free(frame);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
                ret |= ldb_msg_add_value(msg, "clearTextPassword", &pw_utf16, NULL);
@@ -432,10 +442,10 @@ static int pdb_samba_dsdb_replace_by_sam(struct pdb_samba_dsdb_state *state,
                                invalid_history = true;
                        } else {
                                unsigned int i;
-                               static const uint8_t zeros[16];
                                /* Parse the history into the correct format */
                                for (i = 0; i < current_hist_len; i++) {
-                                       if (memcmp(&history[i*PW_HISTORY_ENTRY_LEN], zeros, 16) != 0) {
+                                       if (!all_zero(&history[i*PW_HISTORY_ENTRY_LEN],
+                                                     16)) {
                                                /* If the history is in the old format, with a salted hash, then we can't migrate it to AD format */
                                                invalid_history = true;
                                                break;
@@ -462,7 +472,7 @@ static int pdb_samba_dsdb_replace_by_sam(struct pdb_samba_dsdb_state *state,
                }
                if (changed_lm_pw || changed_nt_pw || changed_history) {
                        /* These attributes can only be modified directly by using a special control */
-                       dsdb_flags = DSDB_BYPASS_PASSWORD_HASH;
+                       dsdb_flags |= DSDB_BYPASS_PASSWORD_HASH;
                }
        }
 
@@ -553,8 +563,25 @@ static int pdb_samba_dsdb_replace_by_sam(struct pdb_samba_dsdb_state *state,
 
        /* This will need work, it is actually a UTF8 'string' with internal NULLs, to handle TS parameters */
        if (need_update(sam, PDB_MUNGEDDIAL)) {
-               ret |= ldb_msg_add_string(msg, "userParameters",
-                                         pdb_get_munged_dial(sam));
+               const char *base64_munged_dial = NULL;
+
+               base64_munged_dial = pdb_get_munged_dial(sam);
+               if (base64_munged_dial != NULL && strlen(base64_munged_dial) > 0) {
+                       struct ldb_val blob;
+
+                       blob = base64_decode_data_blob_talloc(msg,
+                                                       base64_munged_dial);
+                       if (blob.data == NULL) {
+                               DEBUG(0, ("Failed to decode userParameters from "
+                                         "munged dialback string[%s] for %s\n",
+                                         base64_munged_dial,
+                                         ldb_dn_get_linearized(msg->dn)));
+                               talloc_free(frame);
+                               return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+                       }
+                       ret |= ldb_msg_add_steal_value(msg, "userParameters",
+                                                      &blob);
+               }
        }
 
        if (need_update(sam, PDB_COUNTRY_CODE)) {
@@ -614,7 +641,8 @@ static NTSTATUS pdb_samba_dsdb_getsamupriv(struct pdb_samba_dsdb_state *state,
                "sAMAccountName", "displayName", "homeDirectory",
                "homeDrive", "scriptPath", "profilePath", "description",
                "userWorkstations", "comment", "userParameters", "objectSid",
-               "primaryGroupID", "userAccountControl", "logonHours",
+               "primaryGroupID", "userAccountControl",
+               "msDS-User-Account-Control-Computed", "logonHours",
                "badPwdCount", "logonCount", "countryCode", "codePage",
                "unicodePwd", "dBCSPwd", NULL };
 
@@ -631,7 +659,13 @@ static NTSTATUS pdb_samba_dsdb_getsamupriv(struct pdb_samba_dsdb_state *state,
 static NTSTATUS pdb_samba_dsdb_getsampwfilter(struct pdb_methods *m,
                                          struct pdb_samba_dsdb_state *state,
                                          struct samu *sam_acct,
-                                         const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(4, 5)
+                                         const char *exp_fmt, ...)
+                                         PRINTF_ATTRIBUTE(4,5);
+
+static NTSTATUS pdb_samba_dsdb_getsampwfilter(struct pdb_methods *m,
+                                         struct pdb_samba_dsdb_state *state,
+                                         struct samu *sam_acct,
+                                         const char *exp_fmt, ...)
 {
        struct ldb_message *priv;
        NTSTATUS status;
@@ -688,22 +722,18 @@ static NTSTATUS pdb_samba_dsdb_getsampwsid(struct pdb_methods *m,
        NTSTATUS status;
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_samba_dsdb_state);
-       char *sidstr;
-
-       sidstr = dom_sid_string(talloc_tos(), sid);
-       NT_STATUS_HAVE_NO_MEMORY(sidstr);
+       struct dom_sid_buf buf;
 
        status = pdb_samba_dsdb_getsampwfilter(m, state, sam_acct,
                                           "(&(objectsid=%s)(objectclass=user))",
-                                          sidstr);
-       talloc_free(sidstr);
+                                          dom_sid_str_buf(sid, &buf));
        return status;
 }
 
 static NTSTATUS pdb_samba_dsdb_create_user(struct pdb_methods *m,
                                    TALLOC_CTX *mem_ctx,
-                                   const char *name, uint32 acct_flags,
-                                   uint32 *rid)
+                                   const char *name, uint32_t acct_flags,
+                                   uint32_t *rid)
 {
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_samba_dsdb_state);
@@ -734,10 +764,15 @@ static NTSTATUS pdb_samba_dsdb_delete_user(struct pdb_methods *m,
                m->private_data, struct pdb_samba_dsdb_state);
        struct ldb_dn *dn;
        int rc;
+       struct dom_sid_buf buf;
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
 
-       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, pdb_get_user_sid(sam)));
+       dn = ldb_dn_new_fmt(
+               tmp_ctx,
+               state->ldb,
+               "<SID=%s>",
+               dom_sid_str_buf(pdb_get_user_sid(sam), &buf));
        if (!dn || !ldb_dn_validate(dn)) {
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
@@ -756,7 +791,7 @@ static NTSTATUS pdb_samba_dsdb_delete_user(struct pdb_methods *m,
 
 /* This interface takes a fully populated struct samu and places it in
  * the database.  This is not implemented at this time as we need to
- * be careful around the creation of arbitary SIDs (ie, we must ensrue
+ * be careful around the creation of arbitrary SIDs (ie, we must ensure
  * they are not left in a RID pool */
 static NTSTATUS pdb_samba_dsdb_add_sam_account(struct pdb_methods *m,
                                        struct samu *sampass)
@@ -845,8 +880,8 @@ static NTSTATUS pdb_samba_dsdb_rename_sam_account(struct pdb_methods *m,
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-/* This is not implemented, as this module is exptected to be used
- * with auth_samba_dsdb, and this is responible for login counters etc
+/* This is not implemented, as this module is expected to be used
+ * with auth_samba_dsdb, and this is responsible for login counters etc
  *
  */
 static NTSTATUS pdb_samba_dsdb_update_login_attempts(struct pdb_methods *m,
@@ -856,12 +891,17 @@ static NTSTATUS pdb_samba_dsdb_update_login_attempts(struct pdb_methods *m,
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
+static NTSTATUS pdb_samba_dsdb_getgrfilter(struct pdb_methods *m,
+                                          GROUP_MAP *map,
+                                          const char *exp_fmt, ...)
+                                          PRINTF_ATTRIBUTE(3,4);
+
 static NTSTATUS pdb_samba_dsdb_getgrfilter(struct pdb_methods *m, GROUP_MAP *map,
-                                   const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(4, 5)
+                                   const char *exp_fmt, ...)
 {
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_samba_dsdb_state);
-       const char *attrs[] = { "objectSid", "description", "samAccountName", "groupType",
+       const char *attrs[] = { "objectClass", "objectSid", "description", "samAccountName", "groupType",
                                NULL };
        struct ldb_message *msg;
        va_list ap;
@@ -920,15 +960,13 @@ static NTSTATUS pdb_samba_dsdb_getgrfilter(struct pdb_methods *m, GROUP_MAP *map
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
 
-               map->sid_name_use = SID_NAME_DOM_GRP;
-
                ZERO_STRUCT(id_map);
                id_map.sid = sid;
                id_maps[0] = &id_map;
                id_maps[1] = NULL;
 
                status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
-               talloc_free(tmp_ctx);
+
                if (!NT_STATUS_IS_OK(status)) {
                        talloc_free(tmp_ctx);
                        return status;
@@ -979,15 +1017,16 @@ static NTSTATUS pdb_samba_dsdb_getgrsid(struct pdb_methods *m, GROUP_MAP *map,
 {
        char *filter;
        NTSTATUS status;
+       struct dom_sid_buf buf;
 
        filter = talloc_asprintf(talloc_tos(),
                                 "(&(objectsid=%s)(objectclass=group))",
-                                sid_string_talloc(talloc_tos(), &sid));
+                                dom_sid_str_buf(&sid, &buf));
        if (filter == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = pdb_samba_dsdb_getgrfilter(m, map, filter);
+       status = pdb_samba_dsdb_getgrfilter(m, map, "%s", filter);
        TALLOC_FREE(filter);
        return status;
 }
@@ -1010,6 +1049,7 @@ static NTSTATUS pdb_samba_dsdb_getgrgid(struct pdb_methods *m, GROUP_MAP *map,
 
        status = idmap_xids_to_sids(state->idmap_ctx, tmp_ctx, id_maps);
        if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
                return status;
        }
        status = pdb_samba_dsdb_getgrsid(m, map, *id_map.sid);
@@ -1030,14 +1070,14 @@ static NTSTATUS pdb_samba_dsdb_getgrnam(struct pdb_methods *m, GROUP_MAP *map,
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = pdb_samba_dsdb_getgrfilter(m, map, filter);
+       status = pdb_samba_dsdb_getgrfilter(m, map, "%s", filter);
        TALLOC_FREE(filter);
        return status;
 }
 
 static NTSTATUS pdb_samba_dsdb_create_dom_group(struct pdb_methods *m,
                                         TALLOC_CTX *mem_ctx, const char *name,
-                                        uint32 *rid)
+                                        uint32_t *rid)
 {
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_samba_dsdb_state);
@@ -1059,7 +1099,7 @@ static NTSTATUS pdb_samba_dsdb_create_dom_group(struct pdb_methods *m,
 }
 
 static NTSTATUS pdb_samba_dsdb_delete_dom_group(struct pdb_methods *m,
-                                        TALLOC_CTX *mem_ctx, uint32 rid)
+                                        TALLOC_CTX *mem_ctx, uint32_t rid)
 {
        const char *attrs[] = { NULL };
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
@@ -1068,6 +1108,7 @@ static NTSTATUS pdb_samba_dsdb_delete_dom_group(struct pdb_methods *m,
        struct ldb_message *msg;
        struct ldb_dn *dn;
        int rc;
+       struct dom_sid_buf buf;
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
 
@@ -1078,7 +1119,11 @@ static NTSTATUS pdb_samba_dsdb_delete_dom_group(struct pdb_methods *m,
                return NT_STATUS_INTERNAL_ERROR;
        }
 
-       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, &sid));
+       dn = ldb_dn_new_fmt(
+               tmp_ctx,
+               state->ldb,
+               "<SID=%s>",
+               dom_sid_str_buf(&sid, &buf));
        if (!dn || !ldb_dn_validate(dn)) {
                talloc_free(tmp_ctx);
                ldb_transaction_cancel(state->ldb);
@@ -1089,6 +1134,12 @@ static NTSTATUS pdb_samba_dsdb_delete_dom_group(struct pdb_methods *m,
                talloc_free(tmp_ctx);
                ldb_transaction_cancel(state->ldb);
                return NT_STATUS_NO_SUCH_GROUP;
+       } else if (rc != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               DEBUG(10, ("dsdb_search_one failed %s\n",
+                          ldb_errstring(state->ldb)));
+               ldb_transaction_cancel(state->ldb);
+               return NT_STATUS_LDAP(rc);
        }
        rc = ldb_delete(state->ldb, dn);
        if (rc == LDB_ERR_NO_SUCH_OBJECT) {
@@ -1151,11 +1202,16 @@ static NTSTATUS pdb_samba_dsdb_enum_group_members(struct pdb_methods *m,
        uint32_t *members;
        struct ldb_dn *dn;
        NTSTATUS status;
+       struct dom_sid_buf buf;
 
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
 
-       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, group));
+       dn = ldb_dn_new_fmt(
+               tmp_ctx,
+               state->ldb,
+               "<SID=%s>",
+               dom_sid_str_buf(group, &buf));
        if (!dn || !ldb_dn_validate(dn)) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1172,7 +1228,10 @@ static NTSTATUS pdb_samba_dsdb_enum_group_members(struct pdb_methods *m,
        }
 
        *pmembers = members = talloc_array(mem_ctx, uint32_t, num_sids);
-       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(*pmembers, tmp_ctx);
+       if (*pmembers == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
        num_members = 0;
 
        for (i = 0; i < num_sids; i++) {
@@ -1240,10 +1299,11 @@ static NTSTATUS fake_enum_group_memberships(struct pdb_samba_dsdb_state *state,
                if (id_map.xid.type == ID_TYPE_GID || id_map.xid.type == ID_TYPE_BOTH) {
                        gids[0] = id_map.xid.id;
                } else {
+                       struct dom_sid_buf buf1, buf2;
                        DEBUG(1, (__location__
                                  "Group %s, of which %s is a member, could not be converted to a GID\n",
-                                 dom_sid_string(tmp_ctx, &group_sids[0]),
-                                 dom_sid_string(tmp_ctx, &user->user_sid)));
+                                 dom_sid_str_buf(&group_sids[0], &buf1),
+                                 dom_sid_str_buf(&user->user_sid, &buf2)));
                        talloc_free(tmp_ctx);
                        /* We must error out, otherwise a user might
                         * avoid a DENY acl based on a group they
@@ -1347,9 +1407,11 @@ static NTSTATUS pdb_samba_dsdb_enum_group_memberships(struct pdb_methods *m,
                if (id_map.xid.type == ID_TYPE_GID || id_map.xid.type == ID_TYPE_BOTH) {
                        gids[num_groups] = id_map.xid.id;
                } else {
+                       struct dom_sid_buf buf;
                        DEBUG(1, (__location__
                                  "Group %s, of which %s is a member, could not be converted to a GID\n",
-                                 dom_sid_string(tmp_ctx, &group_sids[num_groups]),
+                                 dom_sid_str_buf(&group_sids[num_groups],
+                                                 &buf),
                                  ldb_dn_get_linearized(msg->dn)));
                        talloc_free(tmp_ctx);
                        /* We must error out, otherwise a user might
@@ -1389,17 +1451,29 @@ static NTSTATUS pdb_samba_dsdb_mod_groupmem_by_sid(struct pdb_methods *m,
        struct ldb_message *msg;
        int ret;
        struct ldb_message_element *el;
+       struct dom_sid_buf buf;
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
        msg = ldb_msg_new(tmp_ctx);
-       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(msg, tmp_ctx);
+       if (msg == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       msg->dn = ldb_dn_new_fmt(msg, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, groupsid));
+       msg->dn = ldb_dn_new_fmt(
+               msg,
+               state->ldb,
+               "<SID=%s>",
+               dom_sid_str_buf(groupsid, &buf));
        if (!msg->dn || !ldb_dn_validate(msg->dn)) {
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
        }
-       ret = ldb_msg_add_fmt(msg, "member", "<SID=%s>", dom_sid_string(tmp_ctx, membersid));
+       ret = ldb_msg_add_fmt(
+               msg,
+               "member",
+               "<SID=%s>",
+               dom_sid_str_buf(membersid, &buf));
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
@@ -1428,7 +1502,7 @@ static NTSTATUS pdb_samba_dsdb_mod_groupmem_by_sid(struct pdb_methods *m,
 
 static NTSTATUS pdb_samba_dsdb_mod_groupmem(struct pdb_methods *m,
                                     TALLOC_CTX *mem_ctx,
-                                    uint32 grouprid, uint32 memberrid,
+                                    uint32_t grouprid, uint32_t memberrid,
                                     int mod_op)
 {
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
@@ -1441,9 +1515,15 @@ static NTSTATUS pdb_samba_dsdb_mod_groupmem(struct pdb_methods *m,
        dom_sid = samdb_domain_sid(state->ldb);
 
        groupsid = dom_sid_add_rid(tmp_ctx, dom_sid, grouprid);
-       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(groupsid, tmp_ctx);
+       if (groupsid == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
        membersid = dom_sid_add_rid(tmp_ctx, dom_sid, memberrid);
-       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(membersid, tmp_ctx);
+       if (membersid == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
        status = pdb_samba_dsdb_mod_groupmem_by_sid(m, tmp_ctx, groupsid, membersid, mod_op);
        talloc_free(tmp_ctx);
        return status;
@@ -1451,7 +1531,7 @@ static NTSTATUS pdb_samba_dsdb_mod_groupmem(struct pdb_methods *m,
 
 static NTSTATUS pdb_samba_dsdb_add_groupmem(struct pdb_methods *m,
                                     TALLOC_CTX *mem_ctx,
-                                    uint32 group_rid, uint32 member_rid)
+                                    uint32_t group_rid, uint32_t member_rid)
 {
        return pdb_samba_dsdb_mod_groupmem(m, mem_ctx, group_rid, member_rid,
                                    LDB_FLAG_MOD_ADD);
@@ -1459,14 +1539,14 @@ static NTSTATUS pdb_samba_dsdb_add_groupmem(struct pdb_methods *m,
 
 static NTSTATUS pdb_samba_dsdb_del_groupmem(struct pdb_methods *m,
                                     TALLOC_CTX *mem_ctx,
-                                    uint32 group_rid, uint32 member_rid)
+                                    uint32_t group_rid, uint32_t member_rid)
 {
        return pdb_samba_dsdb_mod_groupmem(m, mem_ctx, group_rid, member_rid,
                                       LDB_FLAG_MOD_DELETE);
 }
 
 static NTSTATUS pdb_samba_dsdb_create_alias(struct pdb_methods *m,
-                                    const char *name, uint32 *rid)
+                                    const char *name, uint32_t *rid)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
@@ -1497,10 +1577,15 @@ static NTSTATUS pdb_samba_dsdb_delete_alias(struct pdb_methods *m,
        struct ldb_message *msg;
        struct ldb_dn *dn;
        int rc;
+       struct dom_sid_buf buf;
        TALLOC_CTX *tmp_ctx = talloc_stackframe();
        NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
 
-       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, sid));
+       dn = ldb_dn_new_fmt(
+               tmp_ctx,
+               state->ldb,
+               "<SID=%s>",
+               dom_sid_str_buf(sid, &buf));
        if (!dn || !ldb_dn_validate(dn)) {
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
@@ -1508,6 +1593,7 @@ static NTSTATUS pdb_samba_dsdb_delete_alias(struct pdb_methods *m,
 
        if (ldb_transaction_start(state->ldb) != LDB_SUCCESS) {
                DEBUG(0, ("Failed to start transaction in dsdb_add_domain_alias(): %s\n", ldb_errstring(state->ldb)));
+               talloc_free(tmp_ctx);
                return NT_STATUS_INTERNAL_ERROR;
        }
 
@@ -1519,6 +1605,12 @@ static NTSTATUS pdb_samba_dsdb_delete_alias(struct pdb_methods *m,
                talloc_free(tmp_ctx);
                ldb_transaction_cancel(state->ldb);
                return NT_STATUS_NO_SUCH_ALIAS;
+       } else if (rc != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               DEBUG(10, ("dsdb_search_one failed %s\n",
+                          ldb_errstring(state->ldb)));
+               ldb_transaction_cancel(state->ldb);
+               return NT_STATUS_LDAP(rc);
        }
        rc = ldb_delete(state->ldb, dn);
        if (rc == LDB_ERR_NO_SUCH_OBJECT) {
@@ -1529,99 +1621,21 @@ static NTSTATUS pdb_samba_dsdb_delete_alias(struct pdb_methods *m,
                DEBUG(10, ("ldb_delete failed %s\n",
                           ldb_errstring(state->ldb)));
                ldb_transaction_cancel(state->ldb);
+               talloc_free(tmp_ctx);
                return NT_STATUS_LDAP(rc);
        }
 
        if (ldb_transaction_commit(state->ldb) != LDB_SUCCESS) {
                DEBUG(0, ("Failed to commit transaction in pdb_samba_dsdb_delete_alias(): %s\n",
                          ldb_errstring(state->ldb)));
+               talloc_free(tmp_ctx);
                return NT_STATUS_INTERNAL_ERROR;
        }
 
+       talloc_free(tmp_ctx);
        return NT_STATUS_OK;
 }
 
-#if 0
-static NTSTATUS pdb_samba_dsdb_set_aliasinfo(struct pdb_methods *m,
-                                     const struct dom_sid *sid,
-                                     struct acct_info *info)
-{
-       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
-               m->private_data, struct pdb_samba_dsdb_state);
-       struct tldap_context *ld;
-       const char *attrs[3] = { "objectSid", "description",
-                                "samAccountName" };
-       struct ldb_message **msg;
-       char *sidstr, *dn;
-       int rc;
-       struct tldap_mod *mods;
-       int num_mods;
-       bool ok;
-
-       ld = pdb_samba_dsdb_ld(state);
-       if (ld == NULL) {
-               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
-       }
-
-       sidstr = sid_binstring(talloc_tos(), sid);
-       NT_STATUS_HAVE_NO_MEMORY(sidstr);
-
-       rc = pdb_samba_dsdb_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 != LDB_SUCCESS) {
-               DEBUG(10, ("ldap_search failed %s\n",
-                          ldb_errstring(state->ldb)));
-               return NT_STATUS_LDAP(rc);
-       }
-       switch talloc_array_length(msg) {
-       case 0:
-               return NT_STATUS_NO_SUCH_ALIAS;
-       case 1:
-               break;
-       default:
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       if (!tldap_entry_dn(msg[0], &dn)) {
-               TALLOC_FREE(msg);
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       mods = NULL;
-       num_mods = 0;
-       ok = true;
-
-       ok &= tldap_make_mod_fmt(
-               msg[0], msg, &num_mods, &mods, "description",
-               "%s", info->acct_desc);
-       ok &= tldap_make_mod_fmt(
-               msg[0], msg, &num_mods, &mods, "samAccountName",
-               "%s", info->acct_name);
-       if (!ok) {
-               TALLOC_FREE(msg);
-               return NT_STATUS_NO_MEMORY;
-       }
-       if (num_mods == 0) {
-               /* no change */
-               TALLOC_FREE(msg);
-               return NT_STATUS_OK;
-       }
-
-       rc = tldap_modify(ld, dn, num_mods, mods, NULL, 0, NULL, 0);
-       TALLOC_FREE(msg);
-       if (rc != LDB_SUCCESS) {
-               DEBUG(10, ("ldap_modify failed: %s\n",
-                          ldb_errstring(state->ldb)));
-               return NT_STATUS_LDAP(rc);
-       }
-       return NT_STATUS_OK;
-}
-#endif
 static NTSTATUS pdb_samba_dsdb_add_aliasmem(struct pdb_methods *m,
                                     const struct dom_sid *alias,
                                     const struct dom_sid *member)
@@ -1655,18 +1669,22 @@ static NTSTATUS pdb_samba_dsdb_enum_aliasmem(struct pdb_methods *m,
        struct ldb_dn *dn;
        unsigned int num_members;
        NTSTATUS status;
+       struct dom_sid_buf buf;
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
 
-       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, alias));
+       dn = ldb_dn_new_fmt(
+               tmp_ctx,
+               state->ldb,
+               "<SID=%s>",
+               dom_sid_str_buf(alias, &buf));
        if (!dn || !ldb_dn_validate(dn)) {
                return NT_STATUS_NO_MEMORY;
        }
 
        status = dsdb_enum_group_mem(state->ldb, mem_ctx, dn, pmembers, &num_members);
-       *pnum_members = num_members;
        if (NT_STATUS_IS_OK(status)) {
-               talloc_steal(mem_ctx, pmembers);
+               *pnum_members = num_members;
        }
        talloc_free(tmp_ctx);
        return status;
@@ -1685,11 +1703,10 @@ static NTSTATUS pdb_samba_dsdb_enum_alias_memberships(struct pdb_methods *m,
        uint32_t *alias_rids = NULL;
        size_t num_alias_rids = 0;
        int i;
-       struct dom_sid *groupSIDs = NULL;
-       unsigned int num_groupSIDs = 0;
+       struct auth_SidAttr *groupSIDs = NULL;
+       uint32_t num_groupSIDs = 0;
        char *filter;
        NTSTATUS status;
-       const char *sid_string;
        const char *sid_dn;
        DATA_BLOB sid_blob;
 
@@ -1700,18 +1717,23 @@ static NTSTATUS pdb_samba_dsdb_enum_alias_memberships(struct pdb_methods *m,
         * either the SAM or BUILTIN
         */
 
-       filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=%u))",
+       filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:"LDB_OID_COMPARATOR_AND":=%u))",
                                 GROUP_TYPE_BUILTIN_LOCAL_GROUP);
        if (filter == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
        for (i = 0; i < num_members; i++) {
-               sid_string = dom_sid_string(tmp_ctx, &members[i]);
-               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sid_string, tmp_ctx);
-
-               sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", sid_string);
-               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sid_dn, tmp_ctx);
+               struct dom_sid_buf buf;
+
+               sid_dn = talloc_asprintf(
+                       tmp_ctx,
+                       "<SID=%s>",
+                       dom_sid_str_buf(&members[i], &buf));
+               if (sid_dn == NULL) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
 
                sid_blob = data_blob_string_const(sid_dn);
 
@@ -1730,7 +1752,7 @@ static NTSTATUS pdb_samba_dsdb_enum_alias_memberships(struct pdb_methods *m,
        }
 
        for (i=0; i<num_groupSIDs; i++) {
-               if (sid_peek_check_rid(domain_sid, &groupSIDs[i],
+               if (sid_peek_check_rid(domain_sid, &groupSIDs[i].sid,
                                       &alias_rids[num_alias_rids])) {
                        num_alias_rids++;;
                }
@@ -1744,7 +1766,7 @@ static NTSTATUS pdb_samba_dsdb_enum_alias_memberships(struct pdb_methods *m,
 static NTSTATUS pdb_samba_dsdb_lookup_rids(struct pdb_methods *m,
                                    const struct dom_sid *domain_sid,
                                    int num_rids,
-                                   uint32 *rids,
+                                   uint32_t *rids,
                                    const char **names,
                                    enum lsa_SidType *lsa_attrs)
 {
@@ -1770,7 +1792,7 @@ static NTSTATUS pdb_samba_dsdb_lookup_names(struct pdb_methods *m,
                                     const struct dom_sid *domain_sid,
                                     int num_names,
                                     const char **pp_names,
-                                    uint32 *rids,
+                                    uint32_t *rids,
                                     enum lsa_SidType *attrs)
 {
        return NT_STATUS_NOT_IMPLEMENTED;
@@ -1847,10 +1869,16 @@ static void pdb_samba_dsdb_search_end(struct pdb_search *search)
        talloc_free(state);
 }
 
+static bool pdb_samba_dsdb_search_filter(struct pdb_methods *m,
+                                        struct pdb_search *search,
+                                        struct pdb_samba_dsdb_search_state **pstate,
+                                        const char *exp_fmt, ...)
+                                        PRINTF_ATTRIBUTE(4, 5);
+
 static bool pdb_samba_dsdb_search_filter(struct pdb_methods *m,
                                     struct pdb_search *search,
                                     struct pdb_samba_dsdb_search_state **pstate,
-                                    const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(4, 5)
+                                    const char *exp_fmt, ...)
 {
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_samba_dsdb_state);
@@ -1918,9 +1946,7 @@ static bool pdb_samba_dsdb_search_filter(struct pdb_methods *m,
                }
                sid_peek_rid(sid, &e->rid);
 
-               e->acct_flags = samdb_result_acct_flags(state->ldb, tmp_ctx,
-                                                       res->msgs[i],
-                                                       ldb_get_default_basedn(state->ldb));
+               e->acct_flags = samdb_result_acct_flags(res->msgs[i], "userAccountControl");
                e->account_name = ldb_msg_find_attr_as_string(
                        res->msgs[i], "samAccountName", NULL);
                if (e->account_name == NULL) {
@@ -1948,7 +1974,7 @@ static bool pdb_samba_dsdb_search_filter(struct pdb_methods *m,
 
 static bool pdb_samba_dsdb_search_users(struct pdb_methods *m,
                                 struct pdb_search *search,
-                                uint32 acct_flags)
+                                uint32_t acct_flags)
 {
        struct pdb_samba_dsdb_search_state *sstate;
        bool ret;
@@ -1996,8 +2022,16 @@ static bool pdb_samba_dsdb_search_aliases(struct pdb_methods *m,
        return true;
 }
 
-static bool pdb_samba_dsdb_uid_to_sid(struct pdb_methods *m, uid_t uid,
-                              struct dom_sid *sid)
+/* 
+ * Instead of taking a gid or uid, this function takes a pointer to a 
+ * unixid. 
+ *
+ * This acts as an in-out variable so that the idmap functions can correctly
+ * receive ID_TYPE_BOTH, and this function ensures cache details are filled
+ * correctly rather than forcing the cache to store ID_TYPE_UID or ID_TYPE_GID. 
+ */
+static bool pdb_samba_dsdb_id_to_sid(struct pdb_methods *m, struct unixid *id,
+                                    struct dom_sid *sid)
 {
        struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
                m->private_data, struct pdb_samba_dsdb_state);
@@ -2009,8 +2043,7 @@ static bool pdb_samba_dsdb_uid_to_sid(struct pdb_methods *m, uid_t uid,
                return false;
        }
 
-       id_map.xid.id = uid;
-       id_map.xid.type = ID_TYPE_UID;
+       id_map.xid = *id;
        id_maps[0] = &id_map;
        id_maps[1] = NULL;
 
@@ -2019,32 +2052,9 @@ static bool pdb_samba_dsdb_uid_to_sid(struct pdb_methods *m, uid_t uid,
                talloc_free(tmp_ctx);
                return false;
        }
-       *sid = *id_map.sid;
-       talloc_free(tmp_ctx);
-       return true;
-}
-
-static bool pdb_samba_dsdb_gid_to_sid(struct pdb_methods *m, gid_t gid,
-                              struct dom_sid *sid)
-{
-       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
-               m->private_data, struct pdb_samba_dsdb_state);
-       NTSTATUS status;
-       struct id_map id_map;
-       struct id_map *id_maps[2];
-       TALLOC_CTX *tmp_ctx = talloc_stackframe();
-       if (!tmp_ctx) {
-               return false;
-       }
-
-       id_map.xid.id = gid;
-       id_map.xid.type = ID_TYPE_GID;
-       id_maps[0] = &id_map;
-       id_maps[1] = NULL;
 
-       status = idmap_xids_to_sids(state->idmap_ctx, tmp_ctx, id_maps);
-       if (!NT_STATUS_IS_OK(status)) {
-               return false;
+       if (id_map.xid.type != ID_TYPE_NOT_SPECIFIED) {
+               id->type = id_map.xid.type;
        }
        *sid = *id_map.sid;
        talloc_free(tmp_ctx);
@@ -2083,10 +2093,10 @@ static bool pdb_samba_dsdb_sid_to_id(struct pdb_methods *m, const struct dom_sid
 
 static uint32_t pdb_samba_dsdb_capabilities(struct pdb_methods *m)
 {
-       return PDB_CAP_STORE_RIDS | PDB_CAP_ADS;
+       return PDB_CAP_STORE_RIDS | PDB_CAP_ADS | PDB_CAP_TRUSTED_DOMAINS_EX;
 }
 
-static bool pdb_samba_dsdb_new_rid(struct pdb_methods *m, uint32 *rid)
+static bool pdb_samba_dsdb_new_rid(struct pdb_methods *m, uint32_t *rid)
 {
        return false;
 }
@@ -2096,140 +2106,1713 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m,
                                      struct dom_sid *sid,
                                      time_t *pass_last_set_time)
 {
-       return false;
-}
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char * const attrs[] = {
+               "securityIdentifier",
+               "flatName",
+               "trustPartner",
+               "trustAuthOutgoing",
+               "whenCreated",
+               "msDS-SupportedEncryptionTypes",
+               "trustAttributes",
+               "trustDirection",
+               "trustType",
+               NULL
+       };
+       struct ldb_message *msg;
+       const struct ldb_val *password_val;
+       int trust_direction_flags;
+       int trust_type;
+       int i;
+       DATA_BLOB password_utf16;
+       struct trustAuthInOutBlob password_blob;
+       struct AuthenticationInformationArray *auth_array;
+       char *password_talloc;
+       size_t password_len;
+       enum ndr_err_code ndr_err;
+       NTSTATUS status;
+       const char *netbios_domain = NULL;
+       const struct dom_sid *domain_sid = NULL;
 
-static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
-                                     const char* domain, const char* pwd,
-                                     const struct dom_sid *sid)
-{
-       return false;
-}
+       status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+                                      attrs, tmp_ctx, &msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               /*
+                * This can be called to work out of a domain is
+                * trusted, rather than just to get the password
+                */
+               DEBUG(2, ("Failed to get trusted domain password for %s - %s.  "
+                         "It may not be a trusted domain.\n", domain,
+                         nt_errstr(status)));
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
 
-static bool pdb_samba_dsdb_del_trusteddom_pw(struct pdb_methods *m,
-                                     const char *domain)
-{
-       return false;
-}
+       netbios_domain = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+       if (netbios_domain == NULL) {
+               DEBUG(2, ("Trusted domain %s has to flatName defined.\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
 
-static NTSTATUS pdb_samba_dsdb_enum_trusteddoms(struct pdb_methods *m,
-                                        TALLOC_CTX *mem_ctx,
-                                        uint32 *num_domains,
-                                        struct trustdom_info ***domains)
-{
-       *num_domains = 0;
-       *domains = NULL;
-       return NT_STATUS_OK;
-}
+       domain_sid = samdb_result_dom_sid(tmp_ctx, msg, "securityIdentifier");
+       if (domain_sid == NULL) {
+               DEBUG(2, ("Trusted domain %s has no securityIdentifier defined.\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
 
-static bool pdb_samba_dsdb_is_responsible_for_wellknown(struct pdb_methods *m)
-{
-       return true;
-}
+       trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
+       if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
+               DBG_WARNING("Trusted domain %s is not an outbound trust.\n",
+                           domain);
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
 
-static void pdb_samba_dsdb_init_methods(struct pdb_methods *m)
-{
-       m->name = "samba_dsdb";
-       m->get_domain_info = pdb_samba_dsdb_get_domain_info;
-       m->getsampwnam = pdb_samba_dsdb_getsampwnam;
-       m->getsampwsid = pdb_samba_dsdb_getsampwsid;
-       m->create_user = pdb_samba_dsdb_create_user;
-       m->delete_user = pdb_samba_dsdb_delete_user;
-       m->add_sam_account = pdb_samba_dsdb_add_sam_account;
-       m->update_sam_account = pdb_samba_dsdb_update_sam_account;
-       m->delete_sam_account = pdb_samba_dsdb_delete_sam_account;
-       m->rename_sam_account = pdb_samba_dsdb_rename_sam_account;
-       m->update_login_attempts = pdb_samba_dsdb_update_login_attempts;
-       m->getgrsid = pdb_samba_dsdb_getgrsid;
-       m->getgrgid = pdb_samba_dsdb_getgrgid;
-       m->getgrnam = pdb_samba_dsdb_getgrnam;
-       m->create_dom_group = pdb_samba_dsdb_create_dom_group;
-       m->delete_dom_group = pdb_samba_dsdb_delete_dom_group;
-       m->add_group_mapping_entry = pdb_samba_dsdb_add_group_mapping_entry;
-       m->update_group_mapping_entry = pdb_samba_dsdb_update_group_mapping_entry;
-       m->delete_group_mapping_entry = pdb_samba_dsdb_delete_group_mapping_entry;
-       m->enum_group_mapping = pdb_samba_dsdb_enum_group_mapping;
-       m->enum_group_members = pdb_samba_dsdb_enum_group_members;
-       m->enum_group_memberships = pdb_samba_dsdb_enum_group_memberships;
-       m->set_unix_primary_group = pdb_samba_dsdb_set_unix_primary_group;
-       m->add_groupmem = pdb_samba_dsdb_add_groupmem;
-       m->del_groupmem = pdb_samba_dsdb_del_groupmem;
-       m->create_alias = pdb_samba_dsdb_create_alias;
-       m->delete_alias = pdb_samba_dsdb_delete_alias;
-       m->get_aliasinfo = pdb_default_get_aliasinfo;
-       m->add_aliasmem = pdb_samba_dsdb_add_aliasmem;
-       m->del_aliasmem = pdb_samba_dsdb_del_aliasmem;
-       m->enum_aliasmem = pdb_samba_dsdb_enum_aliasmem;
-       m->enum_alias_memberships = pdb_samba_dsdb_enum_alias_memberships;
-       m->lookup_rids = pdb_samba_dsdb_lookup_rids;
-       m->lookup_names = pdb_samba_dsdb_lookup_names;
-       m->get_account_policy = pdb_samba_dsdb_get_account_policy;
-       m->set_account_policy = pdb_samba_dsdb_set_account_policy;
-       m->get_seq_num = pdb_samba_dsdb_get_seq_num;
-       m->search_users = pdb_samba_dsdb_search_users;
-       m->search_groups = pdb_samba_dsdb_search_groups;
-       m->search_aliases = pdb_samba_dsdb_search_aliases;
-       m->uid_to_sid = pdb_samba_dsdb_uid_to_sid;
-       m->gid_to_sid = pdb_samba_dsdb_gid_to_sid;
-       m->sid_to_id = pdb_samba_dsdb_sid_to_id;
-       m->capabilities = pdb_samba_dsdb_capabilities;
-       m->new_rid = pdb_samba_dsdb_new_rid;
-       m->get_trusteddom_pw = pdb_samba_dsdb_get_trusteddom_pw;
-       m->set_trusteddom_pw = pdb_samba_dsdb_set_trusteddom_pw;
-       m->del_trusteddom_pw = pdb_samba_dsdb_del_trusteddom_pw;
-       m->enum_trusteddoms = pdb_samba_dsdb_enum_trusteddoms;
-       m->is_responsible_for_wellknown =
-                               pdb_samba_dsdb_is_responsible_for_wellknown;
-}
+       trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
+       if (trust_type == LSA_TRUST_TYPE_MIT) {
+               DBG_WARNING("Trusted domain %s is not an AD trust "
+                           "(trustType == LSA_TRUST_TYPE_MIT).\n", domain);
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
 
-static void free_private_data(void **vp)
-{
-       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
-               *vp, struct pdb_samba_dsdb_state);
-       talloc_unlink(state, state->ldb);
-       return;
-}
+       password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+       if (password_val == NULL) {
+               DEBUG(2, ("Failed to get trusted domain password for %s, "
+                         "attribute trustAuthOutgoing not returned.\n", domain));
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
 
-static NTSTATUS pdb_samba_dsdb_init_secrets(struct pdb_methods *m)
-{
-       struct pdb_domain_info *dom_info;
-       bool ret;
+       ndr_err = ndr_pull_struct_blob(password_val, tmp_ctx, &password_blob,
+                               (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("Failed to get trusted domain password for %s, "
+                         "attribute trustAuthOutgoing could not be parsed %s.\n",
+                         domain,
+                         ndr_map_error2string(ndr_err)));
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
 
-       dom_info = pdb_samba_dsdb_get_domain_info(m, m);
-       if (!dom_info) {
-               return NT_STATUS_UNSUCCESSFUL;
+       auth_array = &password_blob.current;
+
+       for (i=0; i < auth_array->count; i++) {
+               if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
+                       break;
+               }
        }
 
-       secrets_clear_domain_protection(dom_info->name);
-       ret = secrets_store_domain_sid(dom_info->name,
-                                      &dom_info->sid);
-       if (!ret) {
-               goto done;
+       if (i == auth_array->count) {
+               DEBUG(0, ("Trusted domain %s does not have a "
+                         "clear-text password stored\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               return false;
        }
-       ret = secrets_store_domain_guid(dom_info->name,
-                                       &dom_info->guid);
-       if (!ret) {
-               goto done;
+
+       password_utf16 = data_blob_const(auth_array->array[i].AuthInfo.clear.password,
+                                        auth_array->array[i].AuthInfo.clear.size);
+
+       /*
+        * In the future, make this function return a
+        * cli_credentials that can store a MD4 hash with cli_credential_set_nt_hash()
+        * but for now convert to UTF8 and fail if the string can not be converted.
+        *
+        * We can't safely convert the random strings windows uses into
+        * utf8.
+        */
+       if (!convert_string_talloc(tmp_ctx,
+                                  CH_UTF16MUNGED, CH_UTF8,
+                                  password_utf16.data, password_utf16.length,
+                                  (void *)&password_talloc,
+                                  &password_len)) {
+               DEBUG(0, ("FIXME: Could not convert password for trusted domain %s"
+                         " to UTF8. This may be a password set from Windows.\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               return false;
        }
-       ret = secrets_mark_domain_protected(dom_info->name);
-       if (!ret) {
-               goto done;
+       *pwd = SMB_STRNDUP(password_talloc, password_len);
+       if (pass_last_set_time) {
+               *pass_last_set_time = nt_time_to_unix(auth_array->array[i].LastUpdateTime);
        }
 
-done:
-       TALLOC_FREE(dom_info);
-       if (!ret) {
-               return NT_STATUS_UNSUCCESSFUL;
+       if (sid != NULL) {
+               sid_copy(sid, domain_sid);
        }
-       return NT_STATUS_OK;
+
+       TALLOC_FREE(tmp_ctx);
+       return true;
 }
 
-static NTSTATUS pdb_init_samba_dsdb(struct pdb_methods **pdb_method,
-                            const char *location)
+static NTSTATUS pdb_samba_dsdb_get_trusteddom_creds(struct pdb_methods *m,
+                                                   const char *domain,
+                                                   TALLOC_CTX *mem_ctx,
+                                                   struct cli_credentials **_creds)
 {
-       struct pdb_methods *m;
-       struct pdb_samba_dsdb_state *state;
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char * const attrs[] = {
+               "securityIdentifier",
+               "flatName",
+               "trustPartner",
+               "trustAuthOutgoing",
+               "whenCreated",
+               "msDS-SupportedEncryptionTypes",
+               "trustAttributes",
+               "trustDirection",
+               "trustType",
+               NULL
+       };
+       struct ldb_message *msg;
+       const struct ldb_val *password_val;
+       int trust_direction_flags;
+       int trust_type;
+       int i;
+       DATA_BLOB password_utf16 = {};
+       struct samr_Password *password_nt = NULL;
+       uint32_t password_version = 0;
+       DATA_BLOB old_password_utf16 = {};
+       struct samr_Password *old_password_nt = NULL;
+       struct trustAuthInOutBlob password_blob;
+       enum ndr_err_code ndr_err;
        NTSTATUS status;
+       time_t last_set_time = 0;
+       struct cli_credentials *creds = NULL;
+       bool ok;
+       const char *my_netbios_name = NULL;
+       const char *my_netbios_domain = NULL;
+       const char *my_dns_domain = NULL;
+       const char *netbios_domain = NULL;
+       char *account_name = NULL;
+       char *principal_name = NULL;
+       const char *dns_domain = NULL;
+
+       status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+                                      attrs, tmp_ctx, &msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               /*
+                * This can be called to work out of a domain is
+                * trusted, rather than just to get the password
+                */
+               DEBUG(2, ("Failed to get trusted domain password for %s - %s "
+                         "It may not be a trusted domain.\n", domain,
+                         nt_errstr(status)));
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       netbios_domain = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+       if (netbios_domain == NULL) {
+               DEBUG(2, ("Trusted domain %s has to flatName defined.\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       dns_domain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
+
+       trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
+       if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
+               DBG_WARNING("Trusted domain %s is not an outbound trust.\n",
+                           domain);
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
+       if (trust_type == LSA_TRUST_TYPE_MIT) {
+               DBG_WARNING("Trusted domain %s is not an AD trust "
+                           "(trustType == LSA_TRUST_TYPE_MIT).\n", domain);
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+       if (password_val == NULL) {
+               DEBUG(2, ("Failed to get trusted domain password for %s, "
+                         "attribute trustAuthOutgoing not returned.\n", domain));
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       ndr_err = ndr_pull_struct_blob(password_val, tmp_ctx, &password_blob,
+                               (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("Failed to get trusted domain password for %s, "
+                         "attribute trustAuthOutgoing could not be parsed %s.\n",
+                         domain,
+                         ndr_map_error2string(ndr_err)));
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       for (i=0; i < password_blob.current.count; i++) {
+               struct AuthenticationInformation *a =
+                       &password_blob.current.array[i];
+
+               switch (a->AuthType) {
+               case TRUST_AUTH_TYPE_NONE:
+                       break;
+
+               case TRUST_AUTH_TYPE_VERSION:
+                       password_version = a->AuthInfo.version.version;
+                       break;
+
+               case TRUST_AUTH_TYPE_CLEAR:
+                       last_set_time = nt_time_to_unix(a->LastUpdateTime);
+
+                       password_utf16 = data_blob_const(a->AuthInfo.clear.password,
+                                                        a->AuthInfo.clear.size);
+                       password_nt = NULL;
+                       break;
+
+               case TRUST_AUTH_TYPE_NT4OWF:
+                       if (password_utf16.length != 0) {
+                               break;
+                       }
+
+                       last_set_time = nt_time_to_unix(a->LastUpdateTime);
+
+                       password_nt = &a->AuthInfo.nt4owf.password;
+                       break;
+               }
+       }
+
+       for (i=0; i < password_blob.previous.count; i++) {
+               struct AuthenticationInformation *a = &password_blob.previous.array[i];
+
+               switch (a->AuthType) {
+               case TRUST_AUTH_TYPE_NONE:
+                       break;
+
+               case TRUST_AUTH_TYPE_VERSION:
+                       break;
+
+               case TRUST_AUTH_TYPE_CLEAR:
+                       old_password_utf16 = data_blob_const(a->AuthInfo.clear.password,
+                                                        a->AuthInfo.clear.size);
+                       old_password_nt = NULL;
+                       break;
+
+               case TRUST_AUTH_TYPE_NT4OWF:
+                       if (old_password_utf16.length != 0) {
+                               break;
+                       }
+
+                       old_password_nt = &a->AuthInfo.nt4owf.password;
+                       break;
+               }
+       }
+
+       if (password_utf16.length == 0 && password_nt == NULL) {
+               DEBUG(0, ("Trusted domain %s does not have a "
+                         "clear-text nor nt password stored\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       my_netbios_name = lpcfg_netbios_name(state->lp_ctx);
+       my_netbios_domain = lpcfg_workgroup(state->lp_ctx);
+       my_dns_domain = lpcfg_dnsdomain(state->lp_ctx);
+
+       creds = cli_credentials_init(tmp_ctx);
+       if (creds == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ok = cli_credentials_set_workstation(creds, my_netbios_name, CRED_SPECIFIED);
+       if (!ok) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED);
+       if (!ok) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       ok = cli_credentials_set_realm(creds, dns_domain, CRED_SPECIFIED);
+       if (!ok) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (my_dns_domain != NULL && dns_domain != NULL) {
+               cli_credentials_set_secure_channel_type(creds, SEC_CHAN_DNS_DOMAIN);
+               account_name = talloc_asprintf(tmp_ctx, "%s.", my_dns_domain);
+               if (account_name == NULL) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               principal_name = talloc_asprintf(tmp_ctx, "%s$@%s", my_netbios_domain,
+                                                cli_credentials_get_realm(creds));
+               if (principal_name == NULL) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       } else {
+               cli_credentials_set_secure_channel_type(creds, SEC_CHAN_DOMAIN);
+               account_name = talloc_asprintf(tmp_ctx, "%s$", my_netbios_domain);
+               if (account_name == NULL) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               principal_name = NULL;
+       }
+
+       ok = cli_credentials_set_username(creds, account_name, CRED_SPECIFIED);
+       if (!ok) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (principal_name != NULL) {
+               ok = cli_credentials_set_principal(creds, principal_name,
+                                                  CRED_SPECIFIED);
+               if (!ok) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       if (old_password_nt != NULL) {
+               ok = cli_credentials_set_old_nt_hash(creds, old_password_nt);
+               if (!ok) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       if (old_password_utf16.length > 0) {
+               ok = cli_credentials_set_old_utf16_password(creds,
+                                                           &old_password_utf16);
+               if (!ok) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       if (password_nt != NULL) {
+               ok = cli_credentials_set_nt_hash(creds, password_nt,
+                                                CRED_SPECIFIED);
+               if (!ok) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       if (password_utf16.length > 0) {
+               ok = cli_credentials_set_utf16_password(creds,
+                                                       &password_utf16,
+                                                       CRED_SPECIFIED);
+               if (!ok) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       cli_credentials_set_password_last_changed_time(creds, last_set_time);
+       cli_credentials_set_kvno(creds, password_version);
+
+       if (password_utf16.length > 0 && dns_domain != NULL) {
+               /*
+                * Force kerberos if this is an active directory domain
+                */
+               cli_credentials_set_kerberos_state(creds,
+                                                  CRED_USE_KERBEROS_REQUIRED,
+                                                  CRED_SPECIFIED);
+       } else  {
+               /*
+                * TODO: we should allow krb5 with the raw nt hash.
+                */
+               cli_credentials_set_kerberos_state(creds,
+                                                  CRED_USE_KERBEROS_DISABLED,
+                                                  CRED_SPECIFIED);
+       }
+
+       *_creds = talloc_move(mem_ctx, &creds);
+       TALLOC_FREE(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
+                                     const char* domain, const char* pwd,
+                                     const struct dom_sid *sid)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char * const attrs[] = {
+               "trustAuthOutgoing",
+               "trustDirection",
+               "trustType",
+               NULL
+       };
+       struct ldb_message *msg = NULL;
+       int trust_direction_flags;
+       int trust_type;
+       uint32_t i; /* The same type as old_blob.current.count */
+       const struct ldb_val *old_val = NULL;
+       struct trustAuthInOutBlob old_blob = {};
+       uint32_t old_version = 0;
+       uint32_t new_version = 0;
+       DATA_BLOB new_utf16 = {};
+       struct trustAuthInOutBlob new_blob = {};
+       struct ldb_val new_val = {};
+       struct timeval tv = timeval_current();
+       NTTIME now = timeval_to_nttime(&tv);
+       enum ndr_err_code ndr_err;
+       NTSTATUS status;
+       bool ok;
+       int ret;
+
+       ret = ldb_transaction_start(state->ldb);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(2, ("Failed to start transaction.\n"));
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
+
+       ok = samdb_is_pdc(state->ldb);
+       if (!ok) {
+               DEBUG(2, ("Password changes for domain %s are only allowed on a PDC.\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+                                      attrs, tmp_ctx, &msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               /*
+                * This can be called to work out of a domain is
+                * trusted, rather than just to get the password
+                */
+               DEBUG(2, ("Failed to get trusted domain password for %s - %s.  "
+                         "It may not be a trusted domain.\n", domain,
+                         nt_errstr(status)));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
+       if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
+               DBG_WARNING("Trusted domain %s is not an outbound trust, can't set a password.\n",
+                           domain);
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
+       switch (trust_type) {
+       case LSA_TRUST_TYPE_DOWNLEVEL:
+       case LSA_TRUST_TYPE_UPLEVEL:
+               break;
+       default:
+               DEBUG(0, ("Trusted domain %s is of type 0x%X - "
+                         "password changes are not supported\n",
+                         domain, (unsigned)trust_type));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       old_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+       if (old_val != NULL) {
+               ndr_err = ndr_pull_struct_blob(old_val, tmp_ctx, &old_blob,
+                               (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       DEBUG(0, ("Failed to get trusted domain password for %s, "
+                                 "attribute trustAuthOutgoing could not be parsed %s.\n",
+                                 domain,
+                                 ndr_map_error2string(ndr_err)));
+                       TALLOC_FREE(tmp_ctx);
+                       ldb_transaction_cancel(state->ldb);
+                       return false;
+               }
+       }
+
+       for (i=0; i < old_blob.current.count; i++) {
+               struct AuthenticationInformation *a =
+                       &old_blob.current.array[i];
+
+               switch (a->AuthType) {
+               case TRUST_AUTH_TYPE_NONE:
+                       break;
+
+               case TRUST_AUTH_TYPE_VERSION:
+                       old_version = a->AuthInfo.version.version;
+                       break;
+
+               case TRUST_AUTH_TYPE_CLEAR:
+                       break;
+
+               case TRUST_AUTH_TYPE_NT4OWF:
+                       break;
+               }
+       }
+
+       new_version = old_version + 1;
+       ok = convert_string_talloc(tmp_ctx,
+                                  CH_UNIX, CH_UTF16,
+                                  pwd, strlen(pwd),
+                                  (void *)&new_utf16.data,
+                                  &new_utf16.length);
+       if (!ok) {
+               DEBUG(0, ("Failed to generate new_utf16 password for  domain %s\n",
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       if (new_utf16.length < 28) {
+               DEBUG(0, ("new_utf16[%zu] version[%u] for domain %s to short.\n",
+                         new_utf16.length,
+                         (unsigned)new_version,
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+       if (new_utf16.length > 498) {
+               DEBUG(0, ("new_utf16[%zu] version[%u] for domain %s to long.\n",
+                         new_utf16.length,
+                         (unsigned)new_version,
+                         domain));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       new_blob.count = MAX(old_blob.current.count, 2);
+       new_blob.current.array = talloc_zero_array(tmp_ctx,
+                                       struct AuthenticationInformation,
+                                       new_blob.count);
+       if (new_blob.current.array == NULL) {
+               DEBUG(0, ("talloc_zero_array(%u) failed\n",
+                         (unsigned)new_blob.count));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+       new_blob.previous.array = talloc_zero_array(tmp_ctx,
+                                       struct AuthenticationInformation,
+                                       new_blob.count);
+       if (new_blob.current.array == NULL) {
+               DEBUG(0, ("talloc_zero_array(%u) failed\n",
+                         (unsigned)new_blob.count));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       for (i = 0; i < old_blob.current.count; i++) {
+               struct AuthenticationInformation *o =
+                       &old_blob.current.array[i];
+               struct AuthenticationInformation *p =
+                       &new_blob.previous.array[i];
+
+               *p = *o;
+               new_blob.previous.count++;
+       }
+       for (; i < new_blob.count; i++) {
+               struct AuthenticationInformation *pi =
+                       &new_blob.previous.array[i];
+
+               if (i == 0) {
+                       /*
+                        * new_blob.previous is still empty so
+                        * we'll do new_blob.previous = new_blob.current
+                        * below.
+                        */
+                       break;
+               }
+
+               pi->LastUpdateTime = now;
+               pi->AuthType = TRUST_AUTH_TYPE_NONE;
+               new_blob.previous.count++;
+       }
+
+       for (i = 0; i < new_blob.count; i++) {
+               struct AuthenticationInformation *ci =
+                       &new_blob.current.array[i];
+
+               ci->LastUpdateTime = now;
+               switch (i) {
+               case 0:
+                       ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
+                       ci->AuthInfo.clear.size = new_utf16.length;
+                       ci->AuthInfo.clear.password = new_utf16.data;
+                       break;
+               case 1:
+                       ci->AuthType = TRUST_AUTH_TYPE_VERSION;
+                       ci->AuthInfo.version.version = new_version;
+                       break;
+               default:
+                       ci->AuthType = TRUST_AUTH_TYPE_NONE;
+                       break;
+               }
+
+               new_blob.current.count++;
+       }
+
+       if (new_blob.previous.count == 0) {
+               TALLOC_FREE(new_blob.previous.array);
+               new_blob.previous = new_blob.current;
+       }
+
+       ndr_err = ndr_push_struct_blob(&new_val, tmp_ctx, &new_blob,
+                       (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("Failed to generate trustAuthOutgoing for "
+                         "trusted domain password for %s: %s.\n",
+                         domain, ndr_map_error2string(ndr_err)));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       msg->num_elements = 0;
+       ret = ldb_msg_append_value(msg, "trustAuthOutgoing",
+                                  &new_val, LDB_FLAG_MOD_REPLACE);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("ldb_msg_append_value() failed\n"));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       ret = ldb_modify(state->ldb, msg);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Failed to replace trustAuthOutgoing for "
+                         "trusted domain password for %s: %s - %s\n",
+                         domain, ldb_strerror(ret), ldb_errstring(state->ldb)));
+               TALLOC_FREE(tmp_ctx);
+               ldb_transaction_cancel(state->ldb);
+               return false;
+       }
+
+       ret = ldb_transaction_commit(state->ldb);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Failed to commit trustAuthOutgoing for "
+                         "trusted domain password for %s: %s - %s\n",
+                         domain, ldb_strerror(ret), ldb_errstring(state->ldb)));
+               TALLOC_FREE(tmp_ctx);
+               return false;
+       }
+
+       DEBUG(1, ("Added new_version[%u] to trustAuthOutgoing for "
+                 "trusted domain password for %s.\n",
+                 (unsigned)new_version, domain));
+       TALLOC_FREE(tmp_ctx);
+       return true;
+}
+
+static bool pdb_samba_dsdb_del_trusteddom_pw(struct pdb_methods *m,
+                                     const char *domain)
+{
+       return false;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_trusteddoms(struct pdb_methods *m,
+                                        TALLOC_CTX *mem_ctx,
+                                        uint32_t *_num_domains,
+                                        struct trustdom_info ***_domains)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char * const attrs[] = {
+               "securityIdentifier",
+               "flatName",
+               "trustDirection",
+               NULL
+       };
+       struct ldb_result *res = NULL;
+       unsigned int i;
+       struct trustdom_info **domains = NULL;
+       NTSTATUS status;
+       uint32_t di = 0;
+
+       *_num_domains = 0;
+       *_domains = NULL;
+
+       status = dsdb_trust_search_tdos(state->ldb, NULL,
+                                       attrs, tmp_ctx, &res);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("dsdb_trust_search_tdos() - %s ", nt_errstr(status));
+               TALLOC_FREE(tmp_ctx);
+               return status;
+       }
+
+       if (res->count == 0) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_OK;
+       }
+
+       domains = talloc_zero_array(tmp_ctx, struct trustdom_info *,
+                                   res->count);
+       if (domains == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i = 0; i < res->count; i++) {
+               struct ldb_message *msg = res->msgs[i];
+               struct trustdom_info *d = NULL;
+               const char *name = NULL;
+               struct dom_sid *sid = NULL;
+               uint32_t direction;
+
+               d = talloc_zero(domains, struct trustdom_info);
+               if (d == NULL) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               name = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+               if (name == NULL) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+               sid = samdb_result_dom_sid(msg, msg, "securityIdentifier");
+               if (sid == NULL) {
+                       continue;
+               }
+
+               direction = ldb_msg_find_attr_as_uint(msg, "trustDirection", 0);
+               if (!(direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
+                       continue;
+               }
+
+               d->name = talloc_strdup(d, name);
+               if (d->name == NULL) {
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               d->sid = *sid;
+
+               domains[di++] = d;
+       }
+
+       domains = talloc_realloc(domains, domains, struct trustdom_info *, di);
+       *_domains = talloc_move(mem_ctx, &domains);
+       *_num_domains = di;
+       TALLOC_FREE(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_msg_to_trusted_domain(const struct ldb_message *msg,
+                                               TALLOC_CTX *mem_ctx,
+                                               struct pdb_trusted_domain **_d)
+{
+       struct pdb_trusted_domain *d = NULL;
+       const char *str = NULL;
+       struct dom_sid *sid = NULL;
+       const struct ldb_val *val = NULL;
+       uint64_t val64;
+
+       *_d = NULL;
+
+       d = talloc_zero(mem_ctx, struct pdb_trusted_domain);
+       if (d == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+       if (str == NULL) {
+               TALLOC_FREE(d);
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       d->netbios_name = talloc_strdup(d, str);
+       if (d->netbios_name == NULL) {
+               TALLOC_FREE(d);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
+       if (str != NULL) {
+               d->domain_name = talloc_strdup(d, str);
+               if (d->domain_name == NULL) {
+                       TALLOC_FREE(d);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       sid = samdb_result_dom_sid(d, msg, "securityIdentifier");
+       if (sid != NULL) {
+               d->security_identifier = *sid;
+               TALLOC_FREE(sid);
+       }
+
+       val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+       if (val != NULL) {
+               d->trust_auth_outgoing = data_blob_dup_talloc(d, *val);
+               if (d->trust_auth_outgoing.data == NULL) {
+                       TALLOC_FREE(d);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+       val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
+       if (val != NULL) {
+               d->trust_auth_incoming = data_blob_dup_talloc(d, *val);
+               if (d->trust_auth_incoming.data == NULL) {
+                       TALLOC_FREE(d);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       d->trust_direction = ldb_msg_find_attr_as_uint(msg, "trustDirection", 0);
+       d->trust_type = ldb_msg_find_attr_as_uint(msg, "trustType", 0);
+       d->trust_attributes = ldb_msg_find_attr_as_uint(msg, "trustAttributes", 0);
+
+       val64 = ldb_msg_find_attr_as_uint64(msg, "trustPosixOffset", UINT64_MAX);
+       if (val64 != UINT64_MAX) {
+               d->trust_posix_offset = talloc(d, uint32_t);
+               if (d->trust_posix_offset == NULL) {
+                       TALLOC_FREE(d);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               *d->trust_posix_offset = (uint32_t)val64;
+       }
+
+       val64 = ldb_msg_find_attr_as_uint64(msg, "msDS-SupportedEncryptionTypes", UINT64_MAX);
+       if (val64 != UINT64_MAX) {
+               d->supported_enc_type = talloc(d, uint32_t);
+               if (d->supported_enc_type == NULL) {
+                       TALLOC_FREE(d);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               *d->supported_enc_type = (uint32_t)val64;
+       }
+
+       val = ldb_msg_find_ldb_val(msg, "msDS-TrustForestTrustInfo");
+       if (val != NULL) {
+               d->trust_forest_trust_info = data_blob_dup_talloc(d, *val);
+               if (d->trust_forest_trust_info.data == NULL) {
+                       TALLOC_FREE(d);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       *_d = d;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_trusted_domain(struct pdb_methods *m,
+                                                 TALLOC_CTX *mem_ctx,
+                                                 const char *domain,
+                                                 struct pdb_trusted_domain **td)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char * const attrs[] = {
+               "securityIdentifier",
+               "flatName",
+               "trustPartner",
+               "trustAuthOutgoing",
+               "trustAuthIncoming",
+               "trustAttributes",
+               "trustDirection",
+               "trustType",
+               "trustPosixOffset",
+               "msDS-SupportedEncryptionTypes",
+               "msDS-TrustForestTrustInfo",
+               NULL
+       };
+       struct ldb_message *msg = NULL;
+       struct pdb_trusted_domain *d = NULL;
+       NTSTATUS status;
+
+       status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+                                      attrs, tmp_ctx, &msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("dsdb_trust_search_tdo(%s) - %s ",
+                       domain, nt_errstr(status));
+               TALLOC_FREE(tmp_ctx);
+               return status;
+       }
+
+       status = pdb_samba_dsdb_msg_to_trusted_domain(msg, mem_ctx, &d);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain(%s) - %s ",
+                       domain, nt_errstr(status));
+               TALLOC_FREE(tmp_ctx);
+               return status;
+       }
+
+       *td = d;
+       TALLOC_FREE(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_trusted_domain_by_sid(struct pdb_methods *m,
+                                                        TALLOC_CTX *mem_ctx,
+                                                        struct dom_sid *sid,
+                                                        struct pdb_trusted_domain **td)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char * const attrs[] = {
+               "securityIdentifier",
+               "flatName",
+               "trustPartner",
+               "trustAuthOutgoing",
+               "trustAuthIncoming",
+               "trustAttributes",
+               "trustDirection",
+               "trustType",
+               "trustPosixOffset",
+               "msDS-SupportedEncryptionTypes",
+               "msDS-TrustForestTrustInfo",
+               NULL
+       };
+       struct ldb_message *msg = NULL;
+       struct pdb_trusted_domain *d = NULL;
+       struct dom_sid_buf buf;
+       NTSTATUS status;
+
+       status = dsdb_trust_search_tdo_by_sid(state->ldb, sid,
+                                             attrs, tmp_ctx, &msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("dsdb_trust_search_tdo_by_sid(%s) - %s ",
+                       dom_sid_str_buf(sid, &buf),
+                       nt_errstr(status));
+               TALLOC_FREE(tmp_ctx);
+               return status;
+       }
+
+       status = pdb_samba_dsdb_msg_to_trusted_domain(msg, mem_ctx, &d);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain(%s) - %s ",
+                       dom_sid_str_buf(sid, &buf),
+                       nt_errstr(status));
+               TALLOC_FREE(tmp_ctx);
+               return status;
+       }
+
+       *td = d;
+       TALLOC_FREE(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS add_trust_user(TALLOC_CTX *mem_ctx,
+                              struct ldb_context *sam_ldb,
+                              struct ldb_dn *base_dn,
+                              const char *netbios_name,
+                              struct trustAuthInOutBlob *taiob)
+{
+       struct ldb_request *req = NULL;
+       struct ldb_message *msg = NULL;
+       struct ldb_dn *dn = NULL;
+       uint32_t i;
+       int ret;
+       bool ok;
+
+       dn = ldb_dn_copy(mem_ctx, base_dn);
+       if (dn == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       ok = ldb_dn_add_child_fmt(dn, "cn=%s$,cn=users", netbios_name);
+       if (!ok) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       msg = ldb_msg_new(mem_ctx);
+       if (msg == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       msg->dn = dn;
+
+       ret = ldb_msg_add_string(msg, "objectClass", "user");
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = ldb_msg_add_fmt(msg, "samAccountName", "%s$", netbios_name);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = samdb_msg_add_uint(sam_ldb, msg, msg, "userAccountControl",
+                                UF_INTERDOMAIN_TRUST_ACCOUNT);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i = 0; i < taiob->count; i++) {
+               struct AuthenticationInformation *auth_info =
+                       &taiob->current.array[i];
+               const char *attribute = NULL;
+               struct ldb_val v;
+
+               switch (taiob->current.array[i].AuthType) {
+               case TRUST_AUTH_TYPE_NT4OWF:
+                       attribute = "unicodePwd";
+                       v.data = (uint8_t *)&auth_info->AuthInfo.nt4owf.password;
+                       v.length = 16;
+                       break;
+
+               case TRUST_AUTH_TYPE_CLEAR:
+                       attribute = "clearTextPassword";
+                       v.data = auth_info->AuthInfo.clear.password;
+                       v.length = auth_info->AuthInfo.clear.size;
+                       break;
+
+               default:
+                       continue;
+               }
+
+               ret = ldb_msg_add_value(msg, attribute, &v, NULL);
+               if (ret != LDB_SUCCESS) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       /* create the trusted_domain user account */
+       ret = ldb_build_add_req(&req, sam_ldb, mem_ctx, msg, NULL, NULL,
+                               ldb_op_default_callback, NULL);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = ldb_request_add_control(
+               req, DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
+               false, NULL);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = dsdb_autotransaction_request(sam_ldb, req);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0,("Failed to create user record %s: %s\n",
+                        ldb_dn_get_linearized(msg->dn),
+                        ldb_errstring(sam_ldb)));
+
+               switch (ret) {
+               case LDB_ERR_ENTRY_ALREADY_EXISTS:
+                       return NT_STATUS_DOMAIN_EXISTS;
+               case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+                       return NT_STATUS_ACCESS_DENIED;
+               default:
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_set_trusted_domain(struct pdb_methods *methods,
+                                                 const char* domain,
+                                                 const struct pdb_trusted_domain *td)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               methods->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       bool in_txn = false;
+       struct ldb_dn *base_dn = NULL;
+       struct ldb_message *msg = NULL;
+       const char *attrs[] = {
+               NULL
+       };
+       char *netbios_encoded = NULL;
+       char *dns_encoded = NULL;
+       char *sid_encoded = NULL;
+       int ret;
+       struct trustAuthInOutBlob taiob;
+       enum ndr_err_code ndr_err;
+       NTSTATUS status;
+       bool ok;
+
+       base_dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->ldb));
+       if (base_dn == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+       /*
+        * We expect S-1-5-21-A-B-C, but we don't
+        * allow S-1-5-21-0-0-0 as this is used
+        * for claims and compound identities.
+        */
+       ok = dom_sid_is_valid_account_domain(&td->security_identifier);
+       if (!ok) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto out;
+       }
+
+       if (strequal(td->netbios_name, "BUILTIN")) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto out;
+       }
+       if (strequal(td->domain_name, "BUILTIN")) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto out;
+       }
+
+       dns_encoded = ldb_binary_encode_string(tmp_ctx, td->domain_name);
+       if (dns_encoded == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+       netbios_encoded = ldb_binary_encode_string(tmp_ctx, td->netbios_name);
+       if (netbios_encoded == NULL) {
+               status =NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+       sid_encoded = ldap_encode_ndr_dom_sid(tmp_ctx, &td->security_identifier);
+       if (sid_encoded == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ok = samdb_is_pdc(state->ldb);
+       if (!ok) {
+               DBG_ERR("Adding TDO is only allowed on a PDC.\n");
+               TALLOC_FREE(tmp_ctx);
+               status = NT_STATUS_INVALID_DOMAIN_ROLE;
+               goto out;
+       }
+
+       status = dsdb_trust_search_tdo(state->ldb,
+                                      td->netbios_name,
+                                      td->domain_name,
+                                      attrs,
+                                      tmp_ctx,
+                                      &msg);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               DBG_ERR("dsdb_trust_search_tdo returned %s\n",
+                       nt_errstr(status));
+               status = NT_STATUS_INVALID_DOMAIN_STATE;
+               goto out;
+       }
+
+       ret = ldb_transaction_start(state->ldb);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               goto out;
+       }
+       in_txn = true;
+
+       msg = ldb_msg_new(tmp_ctx);
+       if (msg == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       msg->dn = ldb_dn_copy(tmp_ctx, base_dn);
+
+       ok = ldb_dn_add_child_fmt(msg->dn, "cn=%s,cn=System", td->domain_name);
+       if (!ok) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = ldb_msg_add_string(msg, "objectClass", "trustedDomain");
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = ldb_msg_add_string(msg, "flatname", td->netbios_name);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = ldb_msg_add_string(msg, "trustPartner", td->domain_name);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = samdb_msg_add_dom_sid(state->ldb,
+                                   tmp_ctx,
+                                   msg,
+                                   "securityIdentifier",
+                                   &td->security_identifier);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = samdb_msg_add_int(state->ldb,
+                               tmp_ctx,
+                               msg,
+                               "trustType",
+                               td->trust_type);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = samdb_msg_add_int(state->ldb,
+                               tmp_ctx,
+                               msg,
+                               "trustAttributes",
+                               td->trust_attributes);
+       if (ret != LDB_SUCCESS) {
+               status =NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = samdb_msg_add_int(state->ldb,
+                               tmp_ctx,
+                               msg,
+                               "trustDirection",
+                               td->trust_direction);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       if (td->trust_auth_incoming.data != NULL) {
+               ret = ldb_msg_add_value(msg,
+                                       "trustAuthIncoming",
+                                       &td->trust_auth_incoming,
+                                       NULL);
+               if (ret != LDB_SUCCESS) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
+               }
+       }
+       if (td->trust_auth_outgoing.data != NULL) {
+               ret = ldb_msg_add_value(msg,
+                                       "trustAuthOutgoing",
+                                       &td->trust_auth_outgoing,
+                                       NULL);
+               if (ret != LDB_SUCCESS) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
+               }
+       }
+
+       /* create the trusted_domain */
+       ret = ldb_add(state->ldb, msg);
+       switch (ret) {
+       case  LDB_SUCCESS:
+               break;
+
+       case  LDB_ERR_ENTRY_ALREADY_EXISTS:
+               DBG_ERR("Failed to create trusted domain record %s: %s\n",
+                       ldb_dn_get_linearized(msg->dn),
+                       ldb_errstring(state->ldb));
+               status = NT_STATUS_DOMAIN_EXISTS;
+               goto out;
+
+       case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+               DBG_ERR("Failed to create trusted domain record %s: %s\n",
+                       ldb_dn_get_linearized(msg->dn),
+                       ldb_errstring(state->ldb));
+               status = NT_STATUS_ACCESS_DENIED;
+               goto out;
+
+       default:
+               DBG_ERR("Failed to create trusted domain record %s: %s\n",
+                       ldb_dn_get_linearized(msg->dn),
+                       ldb_errstring(state->ldb));
+               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               goto out;
+       }
+
+       ndr_err = ndr_pull_struct_blob(
+               &td->trust_auth_outgoing,
+               tmp_ctx,
+               &taiob,
+               (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
+               goto out;
+       }
+
+       if (td->trust_direction == LSA_TRUST_DIRECTION_INBOUND) {
+               status = add_trust_user(tmp_ctx,
+                                       state->ldb,
+                                       base_dn,
+                                       td->netbios_name,
+                                       &taiob);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto out;
+               }
+       }
+
+       ret = ldb_transaction_commit(state->ldb);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       in_txn = false;
+
+       /*
+        * TODO: Notify winbindd that we have a new trust
+        */
+
+       status = NT_STATUS_OK;
+
+out:
+       if (in_txn) {
+               ldb_transaction_cancel(state->ldb);
+       }
+       TALLOC_FREE(tmp_ctx);
+       return status;
+}
+
+static NTSTATUS delete_trust_user(TALLOC_CTX *mem_ctx,
+                                 struct pdb_samba_dsdb_state *state,
+                                 const char *trust_user)
+{
+       const char *attrs[] = { "userAccountControl", NULL };
+       struct ldb_message **msgs;
+       uint32_t uac;
+       int ret;
+
+       ret = gendb_search(state->ldb,
+                          mem_ctx,
+                          ldb_get_default_basedn(state->ldb),
+                          &msgs,
+                          attrs,
+                          "samAccountName=%s$",
+                          trust_user);
+       if (ret > 1) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       if (ret == 0) {
+               return NT_STATUS_OK;
+       }
+
+       uac = ldb_msg_find_attr_as_uint(msgs[0],
+                                       "userAccountControl",
+                                       0);
+       if (!(uac & UF_INTERDOMAIN_TRUST_ACCOUNT)) {
+               return NT_STATUS_OBJECT_NAME_COLLISION;
+       }
+
+       ret = ldb_delete(state->ldb, msgs[0]->dn);
+       switch (ret) {
+       case LDB_SUCCESS:
+               break;
+       case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+               return NT_STATUS_ACCESS_DENIED;
+       default:
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_del_trusted_domain(struct pdb_methods *methods,
+                                                 const char *domain)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               methods->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       struct pdb_trusted_domain *td = NULL;
+       struct ldb_dn *tdo_dn = NULL;
+       bool in_txn = false;
+       NTSTATUS status;
+       int ret;
+       bool ok;
+
+       status = pdb_samba_dsdb_get_trusted_domain(methods,
+                                                  tmp_ctx,
+                                                  domain,
+                                                  &td);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+                       DBG_ERR("Searching TDO for %s returned %s\n",
+                               domain, nt_errstr(status));
+                       return status;
+               }
+               DBG_NOTICE("No TDO object for %s\n", domain);
+               return NT_STATUS_OK;
+       }
+
+       tdo_dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->ldb));
+       if (tdo_dn == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ok = ldb_dn_add_child_fmt(tdo_dn, "cn=%s,cn=System", domain);
+       if (!ok) {
+               TALLOC_FREE(tmp_ctx);
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       ret = ldb_transaction_start(state->ldb);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               goto out;
+       }
+       in_txn = true;
+
+       ret = ldb_delete(state->ldb, tdo_dn);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_INVALID_HANDLE;
+               goto out;
+       }
+
+       if (td->trust_direction == LSA_TRUST_DIRECTION_INBOUND) {
+               status = delete_trust_user(tmp_ctx, state, domain);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto out;
+               }
+       }
+
+       ret = ldb_transaction_commit(state->ldb);
+       if (ret != LDB_SUCCESS) {
+               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               goto out;
+       }
+       in_txn = false;
+
+       status = NT_STATUS_OK;
+
+out:
+       if (in_txn) {
+               ldb_transaction_cancel(state->ldb);
+       }
+       TALLOC_FREE(tmp_ctx);
+
+       return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_trusted_domains(struct pdb_methods *m,
+                                                   TALLOC_CTX *mem_ctx,
+                                                   uint32_t *_num_domains,
+                                                   struct pdb_trusted_domain ***_domains)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba_dsdb_state);
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       const char * const attrs[] = {
+               "securityIdentifier",
+               "flatName",
+               "trustPartner",
+               "trustAuthOutgoing",
+               "trustAuthIncoming",
+               "trustAttributes",
+               "trustDirection",
+               "trustType",
+               "trustPosixOffset",
+               "msDS-SupportedEncryptionTypes",
+               "msDS-TrustForestTrustInfo",
+               NULL
+       };
+       struct ldb_result *res = NULL;
+       unsigned int i;
+       struct pdb_trusted_domain **domains = NULL;
+       NTSTATUS status;
+       uint32_t di = 0;
+
+       *_num_domains = 0;
+       *_domains = NULL;
+
+       status = dsdb_trust_search_tdos(state->ldb, NULL,
+                                       attrs, tmp_ctx, &res);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("dsdb_trust_search_tdos() - %s ", nt_errstr(status));
+               TALLOC_FREE(tmp_ctx);
+               return status;
+       }
+
+       if (res->count == 0) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_OK;
+       }
+
+       domains = talloc_zero_array(tmp_ctx, struct pdb_trusted_domain *,
+                                   res->count);
+       if (domains == NULL) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i = 0; i < res->count; i++) {
+               struct ldb_message *msg = res->msgs[i];
+               struct pdb_trusted_domain *d = NULL;
+
+               status = pdb_samba_dsdb_msg_to_trusted_domain(msg, domains, &d);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain() - %s ",
+                               nt_errstr(status));
+                       TALLOC_FREE(tmp_ctx);
+                       return status;
+               }
+
+               domains[di++] = d;
+       }
+
+       domains = talloc_realloc(domains, domains, struct pdb_trusted_domain *,
+                                di);
+       *_domains = talloc_move(mem_ctx, &domains);
+       *_num_domains = di;
+       TALLOC_FREE(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static bool pdb_samba_dsdb_is_responsible_for_wellknown(struct pdb_methods *m)
+{
+       return true;
+}
+
+static bool pdb_samba_dsdb_is_responsible_for_everything_else(struct pdb_methods *m)
+{
+       return true;
+}
+
+static void pdb_samba_dsdb_init_methods(struct pdb_methods *m)
+{
+       m->name = "samba_dsdb";
+       m->get_domain_info = pdb_samba_dsdb_get_domain_info;
+       m->getsampwnam = pdb_samba_dsdb_getsampwnam;
+       m->getsampwsid = pdb_samba_dsdb_getsampwsid;
+       m->create_user = pdb_samba_dsdb_create_user;
+       m->delete_user = pdb_samba_dsdb_delete_user;
+       m->add_sam_account = pdb_samba_dsdb_add_sam_account;
+       m->update_sam_account = pdb_samba_dsdb_update_sam_account;
+       m->delete_sam_account = pdb_samba_dsdb_delete_sam_account;
+       m->rename_sam_account = pdb_samba_dsdb_rename_sam_account;
+       m->update_login_attempts = pdb_samba_dsdb_update_login_attempts;
+       m->getgrsid = pdb_samba_dsdb_getgrsid;
+       m->getgrgid = pdb_samba_dsdb_getgrgid;
+       m->getgrnam = pdb_samba_dsdb_getgrnam;
+       m->create_dom_group = pdb_samba_dsdb_create_dom_group;
+       m->delete_dom_group = pdb_samba_dsdb_delete_dom_group;
+       m->add_group_mapping_entry = pdb_samba_dsdb_add_group_mapping_entry;
+       m->update_group_mapping_entry = pdb_samba_dsdb_update_group_mapping_entry;
+       m->delete_group_mapping_entry = pdb_samba_dsdb_delete_group_mapping_entry;
+       m->enum_group_mapping = pdb_samba_dsdb_enum_group_mapping;
+       m->enum_group_members = pdb_samba_dsdb_enum_group_members;
+       m->enum_group_memberships = pdb_samba_dsdb_enum_group_memberships;
+       m->set_unix_primary_group = pdb_samba_dsdb_set_unix_primary_group;
+       m->add_groupmem = pdb_samba_dsdb_add_groupmem;
+       m->del_groupmem = pdb_samba_dsdb_del_groupmem;
+       m->create_alias = pdb_samba_dsdb_create_alias;
+       m->delete_alias = pdb_samba_dsdb_delete_alias;
+       m->get_aliasinfo = pdb_default_get_aliasinfo;
+       m->add_aliasmem = pdb_samba_dsdb_add_aliasmem;
+       m->del_aliasmem = pdb_samba_dsdb_del_aliasmem;
+       m->enum_aliasmem = pdb_samba_dsdb_enum_aliasmem;
+       m->enum_alias_memberships = pdb_samba_dsdb_enum_alias_memberships;
+       m->lookup_rids = pdb_samba_dsdb_lookup_rids;
+       m->lookup_names = pdb_samba_dsdb_lookup_names;
+       m->get_account_policy = pdb_samba_dsdb_get_account_policy;
+       m->set_account_policy = pdb_samba_dsdb_set_account_policy;
+       m->get_seq_num = pdb_samba_dsdb_get_seq_num;
+       m->search_users = pdb_samba_dsdb_search_users;
+       m->search_groups = pdb_samba_dsdb_search_groups;
+       m->search_aliases = pdb_samba_dsdb_search_aliases;
+       m->id_to_sid = pdb_samba_dsdb_id_to_sid;
+       m->sid_to_id = pdb_samba_dsdb_sid_to_id;
+       m->capabilities = pdb_samba_dsdb_capabilities;
+       m->new_rid = pdb_samba_dsdb_new_rid;
+       m->get_trusteddom_pw = pdb_samba_dsdb_get_trusteddom_pw;
+       m->get_trusteddom_creds = pdb_samba_dsdb_get_trusteddom_creds;
+       m->set_trusteddom_pw = pdb_samba_dsdb_set_trusteddom_pw;
+       m->del_trusteddom_pw = pdb_samba_dsdb_del_trusteddom_pw;
+       m->enum_trusteddoms = pdb_samba_dsdb_enum_trusteddoms;
+       m->get_trusted_domain = pdb_samba_dsdb_get_trusted_domain;
+       m->get_trusted_domain_by_sid = pdb_samba_dsdb_get_trusted_domain_by_sid;
+       m->set_trusted_domain = pdb_samba_dsdb_set_trusted_domain;
+       m->del_trusted_domain = pdb_samba_dsdb_del_trusted_domain;
+       m->enum_trusted_domains = pdb_samba_dsdb_enum_trusted_domains;
+       m->is_responsible_for_wellknown =
+                               pdb_samba_dsdb_is_responsible_for_wellknown;
+       m->is_responsible_for_everything_else =
+                               pdb_samba_dsdb_is_responsible_for_everything_else;
+}
+
+static void free_private_data(void **vp)
+{
+       struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+               *vp, struct pdb_samba_dsdb_state);
+       talloc_unlink(state, state->ldb);
+       return;
+}
+
+static NTSTATUS pdb_samba_dsdb_init_secrets(struct pdb_methods *m)
+{
+       struct pdb_domain_info *dom_info;
+       struct dom_sid stored_sid;
+       struct GUID stored_guid;
+       bool sid_exists_and_matches = false;
+       bool guid_exists_and_matches = false;
+       bool ret;
+
+       dom_info = pdb_samba_dsdb_get_domain_info(m, m);
+       if (!dom_info) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ret = secrets_fetch_domain_sid(dom_info->name, &stored_sid);
+       if (ret) {
+               if (dom_sid_equal(&stored_sid, &dom_info->sid)) {
+                       sid_exists_and_matches = true;
+               }
+       }
+
+       if (sid_exists_and_matches == false) {
+               secrets_clear_domain_protection(dom_info->name);
+               ret = secrets_store_domain_sid(dom_info->name,
+                                              &dom_info->sid);
+               ret &= secrets_mark_domain_protected(dom_info->name);
+               if (!ret) {
+                       goto done;
+               }
+       }
+
+       ret = secrets_fetch_domain_guid(dom_info->name, &stored_guid);
+       if (ret) {
+               if (GUID_equal(&stored_guid, &dom_info->guid)) {
+                       guid_exists_and_matches = true;
+               }
+       }
+
+       if (guid_exists_and_matches == false) {
+               secrets_clear_domain_protection(dom_info->name);
+               ret = secrets_store_domain_guid(dom_info->name,
+                                              &dom_info->guid);
+               ret &= secrets_mark_domain_protected(dom_info->name);
+               if (!ret) {
+                       goto done;
+               }
+       }
+
+done:
+       TALLOC_FREE(dom_info);
+       if (!ret) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_init_samba_dsdb(struct pdb_methods **pdb_method,
+                            const char *location)
+{
+       struct pdb_methods *m;
+       struct pdb_samba_dsdb_state *state;
+       NTSTATUS status;
+       char *errstring = NULL;
+       int ret;
 
        if ( !NT_STATUS_IS_OK(status = make_pdb_method( &m )) ) {
                return status;
@@ -2255,21 +3838,23 @@ static NTSTATUS pdb_init_samba_dsdb(struct pdb_methods **pdb_method,
                goto nomem;
        }
 
-       if (location) {
-               state->ldb = samdb_connect_url(state,
-                                  state->ev,
-                                  state->lp_ctx,
-                                  system_session(state->lp_ctx),
-                                  0, location);
-       } else {
-               state->ldb = samdb_connect(state,
-                                  state->ev,
-                                  state->lp_ctx,
-                                  system_session(state->lp_ctx), 0);
+       if (location == NULL) {
+               location = "sam.ldb";
        }
 
+       ret = samdb_connect_url(state,
+                               state->ev,
+                               state->lp_ctx,
+                               system_session(state->lp_ctx),
+                               0,
+                               location,
+                               NULL,
+                               &state->ldb,
+                               &errstring);
+
        if (!state->ldb) {
-               DEBUG(0, ("samdb_connect failed\n"));
+               DEBUG(0, ("samdb_connect failed: %s: %s\n",
+                         errstring, ldb_strerror(ret)));
                status = NT_STATUS_INTERNAL_ERROR;
                goto fail;
        }
@@ -2297,8 +3882,8 @@ fail:
        return status;
 }
 
-NTSTATUS pdb_samba_dsdb_init(void);
-NTSTATUS pdb_samba_dsdb_init(void)
+NTSTATUS pdb_samba_dsdb_init(TALLOC_CTX *);
+NTSTATUS pdb_samba_dsdb_init(TALLOC_CTX *ctx)
 {
        NTSTATUS status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "samba_dsdb",
                                              pdb_init_samba_dsdb);