Fix include paths to new location of libutil.
[bbaumbach/samba-autobuild/.git] / source4 / libnet / libnet_vampire.c
index f4be5013f1c0861880b33bbcdf024454562fae83..7b686ba0072f8e9505043846a043decc651b016d 100644 (file)
@@ -1,13 +1,15 @@
 /* 
    Unix SMB/CIFS implementation.
    
-   Extract the user/system database from a remote SamSync server
+   Extract the user/system database from a remote server
 
-   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+   Copyright (C) Stefan Metzmacher     2004-2006
+   Copyright (C) Brad Henry 2005
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2008
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 
 #include "includes.h"
 #include "libnet/libnet.h"
-#include "librpc/gen_ndr/ndr_netlogon.h"
-#include "librpc/gen_ndr/ndr_samr.h"
-
-
-/**
- * Decrypt and extract the user's passwords.  
- * 
- * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted) passwords back into the structure
- */
-static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
-                        struct creds_CredentialState *creds,
-                        enum netr_SamDatabaseID database,
-                        struct netr_DELTA_ENUM *delta,
-                        char **error_string) 
+#include "lib/events/events.h"
+#include "dsdb/samdb/samdb.h"
+#include "../lib/util/dlinklist.h"
+#include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "system/time.h"
+#include "lib/ldb_wrap.h"
+#include "auth/auth.h"
+#include "param/param.h"
+#include "param/provision.h"
+
+/* 
+List of tasks vampire.py must perform:
+- Domain Join
+ - but don't write the secrets.ldb
+ - results for this should be enough to handle the provision
+- if vampire method is samsync 
+ - Provision using these results 
+  - do we still want to support this NT4 technology?
+- Start samsync with libnet code
+ - provision in the callback 
+- Write out the secrets database, using the code from libnet_Join
+
+*/
+struct vampire_state {
+       const char *netbios_name;
+       struct libnet_JoinDomain *join;
+       struct cli_credentials *machine_account;
+       struct dsdb_schema *self_made_schema;
+       const struct dsdb_schema *schema;
+
+       struct ldb_context *ldb;
+
+       struct {
+               uint32_t object_count;
+               struct drsuapi_DsReplicaObjectListItemEx *first_object;
+               struct drsuapi_DsReplicaObjectListItemEx *last_object;
+       } schema_part;
+
+       const char *targetdir;
+
+       struct loadparm_context *lp_ctx;
+       struct event_context *event_ctx;
+};
+
+static NTSTATUS vampire_prepare_db(void *private_data,
+                                             const struct libnet_BecomeDC_PrepareDB *p)
 {
+       struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
+       struct provision_settings settings;
+       struct provision_result result;
+       NTSTATUS status;
+
+       settings.site_name = p->dest_dsa->site_name;
+       settings.root_dn_str = p->forest->root_dn_str;
+       settings.domain_dn_str = p->domain->dn_str;
+       settings.config_dn_str = p->forest->config_dn_str;
+       settings.schema_dn_str = p->forest->schema_dn_str;
+       settings.netbios_name = p->dest_dsa->netbios_name;
+       settings.realm = s->join->out.realm;
+       settings.domain = s->join->out.domain_name;
+       settings.server_dn_str = p->dest_dsa->server_dn_str;
+       settings.machine_password = generate_random_str(s, 16);
+       settings.targetdir = s->targetdir;
+
+       status = provision_bare(s, s->lp_ctx, &settings, &result);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       s->ldb = result.samdb;
+       s->lp_ctx = result.lp_ctx;
+
+        return NT_STATUS_OK;
+
+
+}
+
+static NTSTATUS vampire_check_options(void *private_data,
+                                            const struct libnet_BecomeDC_CheckOptions *o)
+{
+       struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
+
+       DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
+               s->netbios_name,
+               o->domain->netbios_name, o->domain->dns_name));
+
+       DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
+               o->source_dsa->dns_name, o->source_dsa->site_name));
+
+       DEBUG(0,("Options:crossRef behavior_version[%u]\n"
+                      "\tschema object_version[%u]\n"
+                      "\tdomain behavior_version[%u]\n"
+                      "\tdomain w2k3_update_revision[%u]\n", 
+               o->forest->crossref_behavior_version,
+               o->forest->schema_object_version,
+               o->domain->behavior_version,
+               o->domain->w2k3_update_revision));
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS vampire_apply_schema(struct vampire_state *s,
+                                 const struct libnet_BecomeDC_StoreChunk *c)
+{
+       WERROR status;
+       const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
+       uint32_t object_count;
+       struct drsuapi_DsReplicaObjectListItemEx *first_object;
+       struct drsuapi_DsReplicaObjectListItemEx *cur;
+       uint32_t linked_attributes_count;
+       struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
+       const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
+       struct dsdb_extended_replicated_objects *objs;
+       struct repsFromTo1 *s_dsa;
+       char *tmp_dns_name;
+       struct ldb_message *msg;
+       struct ldb_val prefixMap_val;
+       struct ldb_message_element *prefixMap_el;
+       struct ldb_val schemaInfo_val;
+       uint32_t i;
+       int ret;
+       bool ok;
+
+       DEBUG(0,("Analyze and apply schema objects\n"));
+
+       s_dsa                   = talloc_zero(s, struct repsFromTo1);
+       NT_STATUS_HAVE_NO_MEMORY(s_dsa);
+       s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
+       NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
+
+       switch (c->ctr_level) {
+       case 1:
+               mapping_ctr                     = &c->ctr1->mapping_ctr;
+               object_count                    = s->schema_part.object_count;
+               first_object                    = s->schema_part.first_object;
+               linked_attributes_count         = 0;
+               linked_attributes               = NULL;
+               s_dsa->highwatermark            = c->ctr1->new_highwatermark;
+               s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
+               s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
+               uptodateness_vector             = NULL; /* TODO: map it */
+               break;
+       case 6:
+               mapping_ctr                     = &c->ctr6->mapping_ctr;
+               object_count                    = s->schema_part.object_count;
+               first_object                    = s->schema_part.first_object;
+               linked_attributes_count         = 0; /* TODO: ! */
+               linked_attributes               = NULL; /* TODO: ! */;
+               s_dsa->highwatermark            = c->ctr6->new_highwatermark;
+               s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
+               s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
+               uptodateness_vector             = c->ctr6->uptodateness_vector;
+               break;
+       default:
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       s_dsa->replica_flags            = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
+       memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
+
+       tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+       tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+       s_dsa->other_info->dns_name = tmp_dns_name;
 
-       uint32_t rid = delta->delta_id_union.rid;
-       struct netr_DELTA_USER *user = delta->delta_union.user;
-       struct samr_Password lm_hash;
-       struct samr_Password nt_hash;
-       const char *username = user->account_name.string;
-       NTSTATUS nt_status;
-
-       if (user->lm_password_present) {
-               sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
-               user->lmpassword = lm_hash;
-       }
-
-       if (user->nt_password_present) {
-               sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
-               user->ntpassword = nt_hash;
-       }
-
-       if (user->user_private_info.SensitiveData) {
-               DATA_BLOB data;
-               struct netr_USER_KEYS keys;
-               data.data = user->user_private_info.SensitiveData;
-               data.length = user->user_private_info.DataLength;
-               creds_arcfour_crypt(creds, data.data, data.length);
-               user->user_private_info.SensitiveData = data.data;
-               user->user_private_info.DataLength = data.length;
-
-               nt_status = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
-               if (NT_STATUS_IS_OK(nt_status)) {
-                       if (keys.keys.keys2.lmpassword.length == 16) {
-                               sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0);
-                               user->lmpassword = lm_hash;
-                               user->lm_password_present = True;
+       for (cur = first_object; cur; cur = cur->next_object) {
+               bool is_attr = false;
+               bool is_class = false;
+
+               for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
+                       struct drsuapi_DsReplicaAttribute *a;
+                       uint32_t j;
+                       const char *oid = NULL;
+
+                       a = &cur->object.attribute_ctr.attributes[i];
+                       status = dsdb_map_int2oid(s->self_made_schema, a->attid, s, &oid);
+                       if (!W_ERROR_IS_OK(status)) {
+                               return werror_to_ntstatus(status);
+                       }
+
+                       switch (a->attid) {
+                       case DRSUAPI_ATTRIBUTE_objectClass:
+                               for (j=0; j < a->value_ctr.num_values; j++) {
+                                       uint32_t val = 0xFFFFFFFF;
+
+                                       if (a->value_ctr.values[i].blob
+                                           && a->value_ctr.values[i].blob->length == 4) {
+                                               val = IVAL(a->value_ctr.values[i].blob->data,0);
+                                       }
+
+                                       if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
+                                               is_attr = true;
+                                       }
+                                       if (val == DRSUAPI_OBJECTCLASS_classSchema) {
+                                               is_class = true;
+                                       }
+                               }
+
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               if (is_attr) {
+                       struct dsdb_attribute *sa;
+
+                       sa = talloc_zero(s->self_made_schema, struct dsdb_attribute);
+                       NT_STATUS_HAVE_NO_MEMORY(sa);
+
+                       status = dsdb_attribute_from_drsuapi(s->self_made_schema, &cur->object, s, sa);
+                       if (!W_ERROR_IS_OK(status)) {
+                               return werror_to_ntstatus(status);
                        }
-                       if (keys.keys.keys2.ntpassword.length == 16) {
-                               sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
-                               user->ntpassword = nt_hash;
-                               user->nt_password_present = True;
+
+                       DLIST_ADD_END(s->self_made_schema->attributes, sa, struct dsdb_attribute *);
+               }
+
+               if (is_class) {
+                       struct dsdb_class *sc;
+
+                       sc = talloc_zero(s->self_made_schema, struct dsdb_class);
+                       NT_STATUS_HAVE_NO_MEMORY(sc);
+
+                       status = dsdb_class_from_drsuapi(s->self_made_schema, &cur->object, s, sc);
+                       if (!W_ERROR_IS_OK(status)) {
+                               return werror_to_ntstatus(status);
                        }
-               } else {
-                       *error_string = talloc_asprintf(mem_ctx, "Failed to parse Sensitive Data for %s:\n", username);
-                       dump_data(10, data.data, data.length);
-                       return nt_status;
+
+                       DLIST_ADD_END(s->self_made_schema->classes, sc, struct dsdb_class *);
                }
        }
+
+       /* attach the schema to the ldb */
+       ret = dsdb_set_schema(s->ldb, s->self_made_schema);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_FOOBAR;
+       }
+       /* we don't want to access the self made schema anymore */
+       s->self_made_schema = NULL;
+       s->schema = dsdb_get_schema(s->ldb);
+
+       status = dsdb_extended_replicated_objects_commit(s->ldb,
+                                                        c->partition->nc.dn,
+                                                        mapping_ctr,
+                                                        object_count,
+                                                        first_object,
+                                                        linked_attributes_count,
+                                                        linked_attributes,
+                                                        s_dsa,
+                                                        uptodateness_vector,
+                                                        c->gensec_skey,
+                                                        s, &objs);
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
+               return werror_to_ntstatus(status);
+       }
+
+       if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
+               for (i=0; i < objs->num_objects; i++) {
+                       struct ldb_ldif ldif;
+                       fprintf(stdout, "#\n");
+                       ldif.changetype = LDB_CHANGETYPE_NONE;
+                       ldif.msg = objs->objects[i].msg;
+                       ldb_ldif_write_file(s->ldb, stdout, &ldif);
+                       NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
+               }
+       }
+
+       msg = ldb_msg_new(objs);
+       NT_STATUS_HAVE_NO_MEMORY(msg);
+       msg->dn = objs->partition_dn;
+
+       status = dsdb_get_oid_mappings_ldb(s->schema, msg, &prefixMap_val, &schemaInfo_val);
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("Failed dsdb_get_oid_mappings_ldb(%s)\n", win_errstr(status)));
+               return werror_to_ntstatus(status);
+       }
+
+       /* we only add prefixMap here, because schemaInfo is a replicated attribute and already applied */
+       ret = ldb_msg_add_value(msg, "prefixMap", &prefixMap_val, &prefixMap_el);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_FOOBAR;
+       }
+       prefixMap_el->flags = LDB_FLAG_MOD_REPLACE;
+
+       ret = ldb_modify(s->ldb, msg);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0,("Failed to add prefixMap and schemaInfo %s\n", ldb_strerror(ret)));
+               return NT_STATUS_FOOBAR;
+       }
+
+       talloc_free(s_dsa);
+       talloc_free(objs);
+
+       /* reopen the ldb */
+       talloc_free(s->ldb); /* this also free's the s->schema, because dsdb_set_schema() steals it */
+       s->schema = NULL;
+
+       DEBUG(0,("Reopen the SAM LDB with system credentials and a already stored schema\n"));
+       s->ldb = samdb_connect(s, s->event_ctx, s->lp_ctx, 
+                              system_session(s, s->lp_ctx));
+       if (!s->ldb) {
+               DEBUG(0,("Failed to reopen sam.ldb\n"));
+               return NT_STATUS_INTERNAL_DB_ERROR;
+       }
+
+       /* We must set these up to ensure the replMetaData is written correctly, before our NTDS Settings entry is replicated */
+       ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
+       if (!ok) {
+               DEBUG(0,("Failed to set cached ntds invocationId\n"));
+               return NT_STATUS_FOOBAR;
+       }
+       ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
+       if (!ok) {
+               DEBUG(0,("Failed to set cached ntds objectGUID\n"));
+               return NT_STATUS_FOOBAR;
+       }
+
+       s->schema = dsdb_get_schema(s->ldb);
+       if (!s->schema) {
+               DEBUG(0,("Failed to get loaded dsdb_schema\n"));
+               return NT_STATUS_FOOBAR;
+       }
+
        return NT_STATUS_OK;
 }
 
-/**
- * Decrypt and extract the secrets
- * 
- * The writes decrypted secrets back into the structure
- */
-static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
-                          struct creds_CredentialState *creds,
-                          enum netr_SamDatabaseID database,
-                          struct netr_DELTA_ENUM *delta,
-                          char **error_string) 
+static NTSTATUS vampire_schema_chunk(void *private_data,
+                                           const struct libnet_BecomeDC_StoreChunk *c)
 {
-       struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
-       creds_arcfour_crypt(creds, secret->current_cipher.cipher_data, 
-                           secret->current_cipher.maxlen); 
+       struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
+       WERROR status;
+       const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
+       uint32_t nc_object_count;
+       uint32_t object_count;
+       struct drsuapi_DsReplicaObjectListItemEx *first_object;
+       struct drsuapi_DsReplicaObjectListItemEx *cur;
+       uint32_t nc_linked_attributes_count;
+       uint32_t linked_attributes_count;
+
+       switch (c->ctr_level) {
+       case 1:
+               mapping_ctr                     = &c->ctr1->mapping_ctr;
+               nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
+               object_count                    = c->ctr1->object_count;
+               first_object                    = c->ctr1->first_object;
+               nc_linked_attributes_count      = 0;
+               linked_attributes_count         = 0;
+               break;
+       case 6:
+               mapping_ctr                     = &c->ctr6->mapping_ctr;
+               nc_object_count                 = c->ctr6->nc_object_count;
+               object_count                    = c->ctr6->object_count;
+               first_object                    = c->ctr6->first_object;
+               nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
+               linked_attributes_count         = c->ctr6->linked_attributes_count;
+               break;
+       default:
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
-       creds_arcfour_crypt(creds, secret->old_cipher.cipher_data, 
-                           secret->old_cipher.maxlen); 
+       if (nc_object_count) {
+               DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
+                       c->partition->nc.dn, object_count, nc_object_count,
+                       linked_attributes_count, nc_linked_attributes_count));
+       } else {
+               DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u\n",
+               c->partition->nc.dn, object_count, linked_attributes_count));
+       }
+
+       if (!s->schema) {
+               s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx));
+
+               NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
+
+               status = dsdb_load_oid_mappings_drsuapi(s->self_made_schema, mapping_ctr);
+               if (!W_ERROR_IS_OK(status)) {
+                       return werror_to_ntstatus(status);
+               }
+
+               s->schema = s->self_made_schema;
+       } else {
+               status = dsdb_verify_oid_mappings_drsuapi(s->schema, mapping_ctr);
+               if (!W_ERROR_IS_OK(status)) {
+                       return werror_to_ntstatus(status);
+               }
+       }
+
+       if (!s->schema_part.first_object) {
+               s->schema_part.object_count = object_count;
+               s->schema_part.first_object = talloc_steal(s, first_object);
+       } else {
+               s->schema_part.object_count             += object_count;
+               s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
+                                                                      first_object);
+       }
+       for (cur = first_object; cur->next_object; cur = cur->next_object) {}
+       s->schema_part.last_object = cur;
+
+       if (!c->partition->more_data) {
+               return vampire_apply_schema(s, c);
+       }
 
        return NT_STATUS_OK;
 }
 
-/**
- * Fix up the delta, dealing with encryption issues so that the final
- * callback need only do the printing or application logic
- */
-
-static NTSTATUS fix_delta(TALLOC_CTX *mem_ctx,                 
-                         struct creds_CredentialState *creds,
-                         enum netr_SamDatabaseID database,
-                         struct netr_DELTA_ENUM *delta,
-                         char **error_string)
+static NTSTATUS vampire_store_chunk(void *private_data,
+                                          const struct libnet_BecomeDC_StoreChunk *c)
 {
-       NTSTATUS nt_status = NT_STATUS_OK;
-       *error_string = NULL;
-       switch (delta->delta_type) {
-       case NETR_DELTA_USER:
-       {
-               nt_status = fix_user(mem_ctx, 
-                                    creds,
-                                    database,
-                                    delta,
-                                    error_string);
+       struct vampire_state *s = talloc_get_type(private_data, struct vampire_state);
+       WERROR status;
+       const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
+       uint32_t nc_object_count;
+       uint32_t object_count;
+       struct drsuapi_DsReplicaObjectListItemEx *first_object;
+       uint32_t nc_linked_attributes_count;
+       uint32_t linked_attributes_count;
+       struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
+       const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
+       struct dsdb_extended_replicated_objects *objs;
+       struct repsFromTo1 *s_dsa;
+       char *tmp_dns_name;
+       uint32_t i;
+
+       s_dsa                   = talloc_zero(s, struct repsFromTo1);
+       NT_STATUS_HAVE_NO_MEMORY(s_dsa);
+       s_dsa->other_info       = talloc(s_dsa, struct repsFromTo1OtherInfo);
+       NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
+
+       switch (c->ctr_level) {
+       case 1:
+               mapping_ctr                     = &c->ctr1->mapping_ctr;
+               nc_object_count                 = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
+               object_count                    = c->ctr1->object_count;
+               first_object                    = c->ctr1->first_object;
+               nc_linked_attributes_count      = 0;
+               linked_attributes_count         = 0;
+               linked_attributes               = NULL;
+               s_dsa->highwatermark            = c->ctr1->new_highwatermark;
+               s_dsa->source_dsa_obj_guid      = c->ctr1->source_dsa_guid;
+               s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
+               uptodateness_vector             = NULL; /* TODO: map it */
                break;
-       }
-       case NETR_DELTA_SECRET:
-       {
-               nt_status = fix_secret(mem_ctx, 
-                                      creds,
-                                      database,
-                                      delta,
-                                      error_string);
+       case 6:
+               mapping_ctr                     = &c->ctr6->mapping_ctr;
+               nc_object_count                 = c->ctr6->nc_object_count;
+               object_count                    = c->ctr6->object_count;
+               first_object                    = c->ctr6->first_object;
+               nc_linked_attributes_count      = c->ctr6->nc_linked_attributes_count;
+               linked_attributes_count         = c->ctr6->linked_attributes_count;
+               linked_attributes               = c->ctr6->linked_attributes;
+               s_dsa->highwatermark            = c->ctr6->new_highwatermark;
+               s_dsa->source_dsa_obj_guid      = c->ctr6->source_dsa_guid;
+               s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
+               uptodateness_vector             = c->ctr6->uptodateness_vector;
                break;
-       }
        default:
-               break;
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       s_dsa->replica_flags            = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
+       memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
+
+       tmp_dns_name    = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+       tmp_dns_name    = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+       s_dsa->other_info->dns_name = tmp_dns_name;
+
+       if (nc_object_count) {
+               DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
+                       c->partition->nc.dn, object_count, nc_object_count,
+                       linked_attributes_count, nc_linked_attributes_count));
+       } else {
+               DEBUG(0,("Partition[%s] objects[%u] linked_values[%u\n",
+               c->partition->nc.dn, object_count, linked_attributes_count));
+       }
+
+       status = dsdb_extended_replicated_objects_commit(s->ldb,
+                                                        c->partition->nc.dn,
+                                                        mapping_ctr,
+                                                        object_count,
+                                                        first_object,
+                                                        linked_attributes_count,
+                                                        linked_attributes,
+                                                        s_dsa,
+                                                        uptodateness_vector,
+                                                        c->gensec_skey,
+                                                        s, &objs);
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
+               return werror_to_ntstatus(status);
        }
-       return nt_status;
+
+       if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
+               for (i=0; i < objs->num_objects; i++) {
+                       struct ldb_ldif ldif;
+                       fprintf(stdout, "#\n");
+                       ldif.changetype = LDB_CHANGETYPE_NONE;
+                       ldif.msg = objs->objects[i].msg;
+                       ldb_ldif_write_file(s->ldb, stdout, &ldif);
+                       NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
+               }
+       }
+       talloc_free(s_dsa);
+       talloc_free(objs);
+
+       for (i=0; i < linked_attributes_count; i++) {
+               const struct dsdb_attribute *sa;
+
+               if (!linked_attributes[i].identifier) {
+                       return NT_STATUS_FOOBAR;                
+               }
+
+               if (!linked_attributes[i].value.blob) {
+                       return NT_STATUS_FOOBAR;                
+               }
+
+               sa = dsdb_attribute_by_attributeID_id(s->schema,
+                                                     linked_attributes[i].attid);
+               if (!sa) {
+                       return NT_STATUS_FOOBAR;
+               }
+
+               if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "dump objects", false)) {
+                       DEBUG(0,("# %s\n", sa->lDAPDisplayName));
+                       NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
+                       dump_data(0,
+                               linked_attributes[i].value.blob->data,
+                               linked_attributes[i].value.blob->length);
+               }
+       }
+
+       return NT_STATUS_OK;
 }
 
-NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamSync *r)
+NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 
+                       struct libnet_Vampire *r)
 {
-       NTSTATUS nt_status, dbsync_nt_status;
-       TALLOC_CTX *samsync_ctx, *loop_ctx, *delta_ctx;
-       struct creds_CredentialState *creds;
-       struct netr_DatabaseSync dbsync;
-       struct cli_credentials *machine_account;
-       struct dcerpc_binding *b;
-       struct dcerpc_pipe *p;
-       const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; 
-       int i;
+       struct libnet_JoinDomain *join;
+       struct libnet_set_join_secrets *set_secrets;
+       struct libnet_BecomeDC b;
+       struct vampire_state *s;
+       struct ldb_message *msg;
+       int ldb_ret;
+       uint32_t i;
+       NTSTATUS status;
 
-       /* TODO: This is bogus */
-       const char **bindings = lp_passwordserver();
-       const char *binding;
+       const char *account_name;
+       const char *netbios_name;
+       
+       r->out.error_string = NULL;
 
-       if (bindings && bindings[0]) {
-               binding = bindings[0];
+       s = talloc_zero(mem_ctx, struct vampire_state);
+       if (!s) {
+               return NT_STATUS_NO_MEMORY;
        }
 
-       samsync_ctx = talloc_named(mem_ctx, 0, "SamSync top context");
+       s->lp_ctx = ctx->lp_ctx;
+       s->event_ctx = ctx->event_ctx;
 
-       if (!r->machine_account) { 
-               machine_account = cli_credentials_init(samsync_ctx);
-               if (!machine_account) {
-                       talloc_free(samsync_ctx);
+       join = talloc_zero(s, struct libnet_JoinDomain);
+       if (!join) {
+               return NT_STATUS_NO_MEMORY;
+       }
+               
+       if (r->in.netbios_name != NULL) {
+               netbios_name = r->in.netbios_name;
+       } else {
+               netbios_name = talloc_reference(join, lp_netbios_name(ctx->lp_ctx));
+               if (!netbios_name) {
+                       r->out.error_string = NULL;
+                       talloc_free(s);
                        return NT_STATUS_NO_MEMORY;
                }
-               cli_credentials_set_conf(machine_account);
-               nt_status = cli_credentials_set_machine_account(machine_account);
-               if (!NT_STATUS_IS_OK(nt_status)) {
-                       r->error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
-                       talloc_free(samsync_ctx);
-                       return nt_status;
-               }
-       } else {
-               machine_account = r->machine_account;
        }
 
-       if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
-               r->error_string
-                       = talloc_asprintf(mem_ctx, 
-                                         "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
-                                         
-                                         cli_credentials_get_domain(machine_account),
-                                         cli_credentials_get_secure_channel_type(machine_account));
-               talloc_free(samsync_ctx);
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       account_name = talloc_asprintf(join, "%s$", netbios_name);
+       if (!account_name) {
+               r->out.error_string = NULL;
+               talloc_free(s);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       join->in.domain_name    = r->in.domain_name;
+       join->in.account_name   = account_name;
+       join->in.netbios_name   = netbios_name;
+       join->in.level          = LIBNET_JOINDOMAIN_AUTOMATIC;
+       join->in.acct_type      = ACB_WSTRUST;
+       join->in.recreate_account = false;
+       status = libnet_JoinDomain(ctx, join, join);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->out.error_string = talloc_steal(mem_ctx, join->out.error_string);
+               talloc_free(s);
+               return status;
        }
+       
+       s->join = join;
 
-       /* Connect to DC (take a binding string for now) */
+       s->targetdir = r->in.targetdir;
 
-       nt_status = dcerpc_parse_binding(samsync_ctx, binding, &b);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               r->error_string = talloc_asprintf(mem_ctx, "Bad binding string %s\n", binding);
-               talloc_free(samsync_ctx);
-               return NT_STATUS_INVALID_PARAMETER;
-       }
+       ZERO_STRUCT(b);
+       b.in.domain_dns_name            = join->out.realm;
+       b.in.domain_netbios_name        = join->out.domain_name;
+       b.in.domain_sid                 = join->out.domain_sid;
+       b.in.source_dsa_address         = join->out.samr_binding->host;
+       b.in.dest_dsa_netbios_name      = netbios_name;
 
-       /* We like schannel */
-       b->flags &= ~DCERPC_AUTH_OPTIONS;
-       b->flags |= DCERPC_SCHANNEL | DCERPC_SEAL /* | DCERPC_SCHANNEL_128 */;
+       b.in.callbacks.private_data     = s;
+       b.in.callbacks.check_options    = vampire_check_options;
+       b.in.callbacks.prepare_db       = vampire_prepare_db;
+       b.in.callbacks.schema_chunk     = vampire_schema_chunk;
+       b.in.callbacks.config_chunk     = vampire_store_chunk;
+       b.in.callbacks.domain_chunk     = vampire_store_chunk;
 
-       /* Setup schannel */
-       nt_status = dcerpc_pipe_connect_b(samsync_ctx, &p, b, 
-                                         DCERPC_NETLOGON_UUID,
-                                         DCERPC_NETLOGON_VERSION,
-                                         machine_account, ctx->event_ctx);
+       status = libnet_BecomeDC(ctx, s, &b);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
+               talloc_free(s);
+               return status;
+       }
 
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               talloc_free(samsync_ctx);
-               return nt_status;
+       msg = ldb_msg_new(s);
+       if (!msg) {
+               printf("ldb_msg_new() failed\n");
+               talloc_free(s);
+               return NT_STATUS_NO_MEMORY;
+       }
+       msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
+       if (!msg->dn) {
+               printf("ldb_msg_new(@ROOTDSE) failed\n");
+               talloc_free(s);
+               return NT_STATUS_NO_MEMORY;
        }
 
-       /* get NETLOGON credentails */
+       ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
+       if (ldb_ret != LDB_SUCCESS) {
+               printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
+               talloc_free(s);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               r->error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
-               talloc_free(samsync_ctx);
-               return nt_status;
+       for (i=0; i < msg->num_elements; i++) {
+               msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
        }
 
-       dbsync.in.logon_server = talloc_asprintf(samsync_ctx, "\\\\%s", dcerpc_server_name(p));
-       dbsync.in.computername = cli_credentials_get_workstation(machine_account);
-       dbsync.in.preferredmaximumlength = (uint32_t)-1;
-       ZERO_STRUCT(dbsync.in.return_authenticator);
+       printf("mark ROOTDSE with isSynchronized=TRUE\n");
+       ldb_ret = ldb_modify(s->ldb, msg);
+       if (ldb_ret != LDB_SUCCESS) {
+               printf("ldb_modify() failed: %d\n", ldb_ret);
+               talloc_free(s);
+               return NT_STATUS_INTERNAL_DB_ERROR;
+       }
 
-       for (i=0;i< ARRAY_SIZE(database_ids); i++) { 
-               dbsync.in.sync_context = 0;
-               dbsync.in.database_id = database_ids[i]; 
+       set_secrets = talloc_zero(s, struct libnet_set_join_secrets);
+       if (!set_secrets) {
+               return NT_STATUS_NO_MEMORY;
+       }
                
-               do {
-                       int d;
-                       loop_ctx = talloc_named(samsync_ctx, 0, "DatabaseSync loop context");
-                       creds_client_authenticator(creds, &dbsync.in.credential);
-                       
-                       dbsync_nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync);
-                       if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
-                           !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
-                               r->error_string = talloc_asprintf(samsync_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
-                               talloc_free(samsync_ctx);
-                               return nt_status;
-                       }
-                       
-                       if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
-                               r->error_string = talloc_strdup(samsync_ctx, "Credential chaining failed");
-                               talloc_free(samsync_ctx);
-                               return NT_STATUS_ACCESS_DENIED;
-                       }
-                       
-                       dbsync.in.sync_context = dbsync.out.sync_context;
-                       
-                       for (d=0; d < dbsync.out.delta_enum_array->num_deltas; d++) {
-                               char *error_string = NULL;
-                               delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
-                               nt_status = fix_delta(delta_ctx, 
-                                                     creds, 
-                                                     dbsync.in.database_id,
-                                                     &dbsync.out.delta_enum_array->delta_enum[d], 
-                                                     &error_string);
-                               if (!NT_STATUS_IS_OK(nt_status)) {
-                                       r->error_string = talloc_steal(samsync_ctx, error_string);
-                                       talloc_free(samsync_ctx);
-                                       return nt_status;
-                               }
-                               nt_status = r->delta_fn(delta_ctx, 
-                                                                r->fn_ctx,
-                                                                creds,
-                                                                dbsync.in.database_id,
-                                                                &dbsync.out.delta_enum_array->delta_enum[d], 
-                                                                &error_string);
-                               if (!NT_STATUS_IS_OK(nt_status)) {
-                                       r->error_string = talloc_steal(samsync_ctx, error_string);
-                                       talloc_free(samsync_ctx);
-                                       return nt_status;
-                               }
-                               talloc_free(delta_ctx);
-                       }
-                       talloc_free(loop_ctx);
-               } while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
-               nt_status = dbsync_nt_status;
+       set_secrets->in.domain_name = join->out.domain_name;
+       set_secrets->in.realm = join->out.realm;
+       set_secrets->in.account_name = account_name;
+       set_secrets->in.netbios_name = netbios_name;
+       set_secrets->in.join_type = SEC_CHAN_BDC;
+       set_secrets->in.join_password = join->out.join_password;
+       set_secrets->in.kvno = join->out.kvno;
+       set_secrets->in.domain_sid = join->out.domain_sid;
+       
+       status = libnet_set_join_secrets(ctx, set_secrets, set_secrets);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->out.error_string = talloc_steal(mem_ctx, set_secrets->out.error_string);
+               talloc_free(s);
+               return status;
        }
-       talloc_free(samsync_ctx);
-       return nt_status;
-}
 
+       r->out.domain_name = talloc_steal(r, join->out.domain_name);
+       r->out.domain_sid = talloc_steal(r, join->out.domain_sid);
+       talloc_free(s);
+       
+       return NT_STATUS_OK;
+
+}