docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source3 / passdb / pdb_samba_dsdb.c
index cfa492b442ab099cbe7f2841c416902ddadba843..8ed5799ac895c1301b813eb9d0b472221311d521 100644 (file)
@@ -40,6 +40,8 @@
 #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;
@@ -153,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 *)
@@ -163,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;
        }
@@ -723,15 +722,11 @@ 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;
 }
 
@@ -769,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;
@@ -791,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)
@@ -880,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,
@@ -1017,10 +1017,11 @@ 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;
        }
@@ -1107,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);
 
@@ -1117,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);
@@ -1128,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) {
@@ -1190,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;
        }
@@ -1282,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
@@ -1389,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
@@ -1431,6 +1451,7 @@ 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);
@@ -1439,12 +1460,20 @@ static NTSTATUS pdb_samba_dsdb_mod_groupmem_by_sid(struct pdb_methods *m,
                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;
@@ -1548,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;
@@ -1571,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) {
@@ -1596,87 +1636,6 @@ static NTSTATUS pdb_samba_dsdb_delete_alias(struct pdb_methods *m,
        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)
@@ -1710,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;
@@ -1740,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;
 
@@ -1755,20 +1717,19 @@ 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]);
-               if (sid_string == NULL) {
-                       TALLOC_FREE(tmp_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
+               struct dom_sid_buf buf;
 
-               sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", sid_string);
+               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;
@@ -1791,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++;;
                }
@@ -2132,7 +2093,7 @@ 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_t *rid)
@@ -2207,17 +2168,16 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m,
 
        trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
        if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
-               DEBUG(2, ("Trusted domain %s is is not an outbound trust.\n",
-                         domain));
+               DBG_WARNING("Trusted domain %s is not an outbound trust.\n",
+                           domain);
                TALLOC_FREE(tmp_ctx);
                return false;
        }
 
        trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
        if (trust_type == LSA_TRUST_TYPE_MIT) {
-               DEBUG(1, ("Trusted domain %s is is not an AD trust "
-                         "(trustType == LSA_TRUST_TYPE_MIT).\n",
-                         domain));
+               DBG_WARNING("Trusted domain %s is not an AD trust "
+                           "(trustType == LSA_TRUST_TYPE_MIT).\n", domain);
                TALLOC_FREE(tmp_ctx);
                return false;
        }
@@ -2234,7 +2194,7 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m,
                                (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 coult not be parsed %s.\n",
+                         "attribute trustAuthOutgoing could not be parsed %s.\n",
                          domain,
                          ndr_map_error2string(ndr_err)));
                TALLOC_FREE(tmp_ctx);
@@ -2362,17 +2322,16 @@ static NTSTATUS pdb_samba_dsdb_get_trusteddom_creds(struct pdb_methods *m,
 
        trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
        if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
-               DEBUG(2, ("Trusted domain %s is is not an outbound trust.\n",
-                         domain));
+               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) {
-               DEBUG(1, ("Trusted domain %s is is not an AD trust "
-                         "(trustType == LSA_TRUST_TYPE_MIT).\n",
-                         domain));
+               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;
        }
@@ -2389,7 +2348,7 @@ static NTSTATUS pdb_samba_dsdb_get_trusteddom_creds(struct pdb_methods *m,
                                (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 coult not be parsed %s.\n",
+                         "attribute trustAuthOutgoing could not be parsed %s.\n",
                          domain,
                          ndr_map_error2string(ndr_err)));
                TALLOC_FREE(tmp_ctx);
@@ -2571,13 +2530,15 @@ static NTSTATUS pdb_samba_dsdb_get_trusteddom_creds(struct pdb_methods *m,
                 * Force kerberos if this is an active directory domain
                 */
                cli_credentials_set_kerberos_state(creds,
-                                                  CRED_MUST_USE_KERBEROS);
+                                                  CRED_USE_KERBEROS_REQUIRED,
+                                                  CRED_SPECIFIED);
        } else  {
                /*
                 * TODO: we should allow krb5 with the raw nt hash.
                 */
                cli_credentials_set_kerberos_state(creds,
-                                                  CRED_DONT_USE_KERBEROS);
+                                                  CRED_USE_KERBEROS_DISABLED,
+                                                  CRED_SPECIFIED);
        }
 
        *_creds = talloc_move(mem_ctx, &creds);
@@ -2601,7 +2562,7 @@ static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
        struct ldb_message *msg = NULL;
        int trust_direction_flags;
        int trust_type;
-       int i;
+       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;
@@ -2649,8 +2610,8 @@ static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
 
        trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
        if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
-               DEBUG(2, ("Trusted domain %s is is not an outbound trust, can't set a password.\n",
-                         domain));
+               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;
@@ -2676,7 +2637,7 @@ static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
                                (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 coult not be parsed %s.\n",
+                                 "attribute trustAuthOutgoing could not be parsed %s.\n",
                                  domain,
                                  ndr_map_error2string(ndr_err)));
                        TALLOC_FREE(tmp_ctx);
@@ -2827,18 +2788,10 @@ static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
        }
 
        msg->num_elements = 0;
-       ret = ldb_msg_add_empty(msg, "trustAuthOutgoing",
-                               LDB_FLAG_MOD_REPLACE, NULL);
-       if (ret != LDB_SUCCESS) {
-               DEBUG(0, ("ldb_msg_add_empty() failed\n"));
-               TALLOC_FREE(tmp_ctx);
-               ldb_transaction_cancel(state->ldb);
-               return false;
-       }
-       ret = ldb_msg_add_value(msg, "trustAuthOutgoing",
-                               &new_val, NULL);
+       ret = ldb_msg_append_value(msg, "trustAuthOutgoing",
+                                  &new_val, LDB_FLAG_MOD_REPLACE);
        if (ret != LDB_SUCCESS) {
-               DEBUG(0, ("ldb_msg_add_value() failed\n"));
+               DEBUG(0, ("ldb_msg_append_value() failed\n"));
                TALLOC_FREE(tmp_ctx);
                ldb_transaction_cancel(state->ldb);
                return false;
@@ -2878,11 +2831,841 @@ static bool pdb_samba_dsdb_del_trusteddom_pw(struct pdb_methods *m,
 
 static NTSTATUS pdb_samba_dsdb_enum_trusteddoms(struct pdb_methods *m,
                                         TALLOC_CTX *mem_ctx,
-                                        uint32_t *num_domains,
-                                        struct trustdom_info ***domains)
+                                        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)
 {
-       *num_domains = 0;
-       *domains = NULL;
+       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;
 }
 
@@ -2947,6 +3730,11 @@ static void pdb_samba_dsdb_init_methods(struct pdb_methods *m)
        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 =
@@ -3023,6 +3811,8 @@ static NTSTATUS pdb_init_samba_dsdb(struct pdb_methods **pdb_method,
        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;
@@ -3048,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;
        }